如何在运行时确定泛型参数是否可为空?我希望NullabilityInfoContext类可以解决这个问题,但这也不起作用。
有解决办法吗?
using System.Reflection;
namespace ConsoleApp;
public class Item<T>
{
public required T Value { get; init; }
public bool IsNullable()
{
var nullabilityInfoContext = new NullabilityInfoContext();
var propertyInfo = this.GetType().GetProperty(nameof(Value));
var nullabilityInfo = nullabilityInfoContext.Create(propertyInfo);
return nullabilityInfo.ReadState == NullabilityState.Nullable;
}
}
internal class Program
{
static void Main()
{
var nullable = new Item<string?>() { Value = null };
var notnull = new Item<string>() { Value = "" };
Console.WriteLine($"nullable is nullable: {nullable.IsNullable()}");
Console.WriteLine($"notnull is nullable: {notnull.IsNullable()}");
// Output:
// nullable is nullable: True
// notnull is nullable: True
}
}
3条答案
按热度按时间pokxtpni1#
这是一个相当棘手但很好的问题。我担心目前你想要实现的是不可能的,当泛型
T
是引用类型时,你不能检查泛型的显式?
为空性。字符串是引用类型。当T
是一个值类型时,你的代码工作得很好:你可以阅读
NullabilityInfoContext
的详细信息here,这是该功能的拉取请求。泛型类型T的可空性应该由用户跟踪,字段声明List<string?> list或Listlist将具有类型参数为空性信息,但其他List API调用的为空性应由用户跟踪< string>。例如,对于list.Add(T item),item的可空性将被评估如下:
1.如果声明有?即GenericType<T?>(即使T是值类型,它也是可空值类型)
1.当可空性上下文启用并且T的具体类型是ref类型或可空值类型时,T对于GenericType是可空的。(在这种情况下,List.Add(T item)的参数T的可空性对于List和List<string?>示例,我们可能需要此场景的第四个空性状态)
1.当具体T为不可空值类型时,T对于GenericType为NotNull
1.当可空性上下文禁用且T的具体类型为ref类型时,T对于GenericType为Unknown
1.对于开放泛型,其行为与T的ref类型相同
但是,当引用类型不是泛型时,确定引用类型的显式可为空性没有问题。
xqkwcwgp2#
NullabilityInfoContext
“提供用于从反射成员填充为空性信息和上下文的API:ParameterInfo、FieldInfo、PropertyInfo和EventInfo。”它通过查看关联类型本身的反射信息,并通过检查与属性等事物关联的附加元数据(据我所知,是某种隐藏的属性)来实现这一点。
因此,如果您使用真正的
Nullable<>
泛型类型,如DoubleL的示例中所示,其中int?
实际上是Nullable<int>
,则在运行时,Value属性返回Nullable<int>
。但这对于
String
这样的引用类型不起作用:可空引用类型不是新的类类型,而是对现有引用类型的注解。编译器使用这些注解来帮助您查找代码中潜在的空引用错误。不可空引用类型和可空引用类型在运行时没有区别。
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/nullable-reference-types#nullable-references-and-static-analysis
那么属性上的属性又是什么呢?好吧,这是绑定到属性,而不是泛型类型。如果包含了足够的类信息,使其知道泛型类型不能为null,则它将查看属性的签名本身,以确定属性是否可为null。例如:
但是,如果
T
是一个引用类型,那么它总是可以为null。在运行时没有足够的可用数据来完成您要做的事情。Item<string>
和Item<string?>
在运行时没有区别。62lalag43#
你的解决方案是正确的。
这里的问题是,类型“string”是一个引用类型,默认情况下它可以为null。换句话说,“字符串”和“字符串?“,两者都可以为空。
如果你尝试运行你的例子:
会很好。