请注意,有一些很好的方法可以检查适用于值类型的“旧”可空类型,这些类型在 Stack Overflow 上有详细记录。
然后,我将只关注可空 reference 类型,并提供检查其中一种是否有效的方法。
让我先总结一下我的问题,因为它们很重要。
与新功能的名称相反,可空引用 types 不是关于 types,而是关于这些类型的 things用于。这些东西是:
现在,这当然也适用于局部变量,但您需要一个完整的“另一种内省”来处理解码指令。我不知道这种信息是如何被编码在局部变量的实际指令中的。
好的,那么,让我们看看一些代码(顺便说一句,我正在使用 LINQPad 和 Roslyn 实验模式来测试所有这些):
public string? Nullable;
public string NonNullable;
这是两个公共字段。忽略这是否是一个好主意。您将如何检查这些字段的类型并检测是否存在此问号?
好吧,让我们试试简单的路线:
Type nullable = GetType().GetField("Nullable").FieldType;
Type nonNullable = GetType().GetField("NonNullable").FieldType;
Console.WriteLine(ReferenceEquals(nullable, nonNullable));
运行它给了我:
True
很明显这是行不通的。 Type 对象是完全相同的instance。他们不只是比较相等,我得到了同样的东西,没有区别。基本上,FieldType 忽略了这个问号的存在与否。
我上面的 cmets 有一些细节,但主要原因是所有现有的 nuget 包,因此编译的代码仍然可以使用这个新的支持。不需要重写任何代码来突然处理像NullableReferenceType<T> 这样的事情。 这是一件好事,但也意味着您仍将传递空引用并从现有的 nuget 包中取回它们。
好的,那么,我们将如何检测到这一点?答案是关于可空性的信息并不附加到类型上,正如我上面提到的,而是附加到具有类型的事物,在这种情况下是字段。
让我们在这些字段上显示属性(我再次使用 LINQPad):
GetType().GetField("Nullable").GetCustomAttributes().Dump();
GetType().GetField("NonNullable").GetCustomAttributes().Dump();
这给出了这个输出:
正如您在此处看到的,Nullable 字段有一个附加属性,NullableAttribute。我必须承认我不知道其他属性是什么,我将不得不进行更多调查。
这个NullableAttribute 属性比这个简单示例显示的要复杂得多,因为它有一个带有bool 值的集合属性。让我们看一个稍微复杂一点的例子:
public List<string>? Nullable1;
public List<string?>? Nullable2;
这里,两个字段都是对列表的可空引用,不同之处在于我说过其中一个列表包含对字符串的可空引用,而另一个则没有。
以下是对这些收藏的一些反思:
GetType().GetField("Nullable1").GetCustomAttributesData().Dump();
GetType().GetField("Nullable2").GetCustomAttributesData().Dump();
及其输出:
在这里你可以看到这个集合中的 second 元素有所不同(我已经用红色“圈出”它们......矩形......),我希望第一个元素适用于列表,第二个适用于第一个泛型类型参数。如果您有包含泛型类型的泛型列表,则参数的数量会相应增加。
您还可以找到有关此excellent blog post by Rico Suter 的更多信息。