我试图在运行时检测某个类型是否可以为空,以将该类型转换为相应的GraphQL类型,例如:
启用了可空引用类型 :
string
转换为String!
string?
转换为String
具有可空引用类型已禁用:
string
转换为String
NonNull<string>
转换为String!
(NonNull
是自定义库类型)我无法适应检测到类型为空的代码:
bool isNullable = !typeInfo.IsValueType;
如何更改它,使其与启用和禁用的可为空的引用类型一起使用?
答案 0 :(得分:2)
请注意,有很好的方法来检查适用于值类型的“旧的”可为空类型,这些类型已在Stack Overflow上详细记录。
然后我将只关注可空的 reference 类型,并提供检查其中一种是否有效的方法。
让我首先总结一下我对这个问题的评论,因为它们很重要。
与新功能的名称相反,可为空的引用 types 与 types 无关,而是与 things 有关。用于。这些事物是:
现在,这当然也适用于局部变量,但是您需要一种整体的“内省”来处理解码指令。我不知道这种信息是如何编码的,甚至在实际的局部变量指令中也没有编码。
好的,接下来,让我们来看一些代码(顺便说一句,我在罗斯林实验模式下使用LINQPad来测试所有这些代码):
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
会忽略此问号的存在与否。
我在上面的评论中包含了一些细节,但是主要原因是所有现有的nuget软件包,因此,编译后的代码仍可在此新支持下使用。无需重写任何代码即可突然处理类似NullableReferenceType<T>
之类的代码。 这是一件好事,但这也意味着您仍将传递空引用,并从现有的nuget包中获取空引用。
好的,那么,我们如何检测到这一点?答案是,如上所述,关于可空性的信息不是附加到类型上,而是附加到具有该类型的 thing 上,在本例中是字段。
让我们在这些字段上显示属性(再次使用LINQPad):
GetType().GetField("Nullable").GetCustomAttributes().Dump();
GetType().GetField("NonNullable").GetCustomAttributes().Dump();
这给出了这个输出:
如您在此处看到的,“可为空”字段具有一个附加属性NullableAttribute
。我必须承认,我不知道其他属性的含义,我将不得不进行更多研究。
此NullableAttribute
属性比此简单示例显示的要复杂得多,因为它具有带有bool
值的collection属性。让我们看一个稍微复杂的例子:
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的更多信息。