如何检测类型在运行时是否可以为空? [英] How to detect whether a type can be nullable at runtime?

查看:92
本文介绍了如何检测类型在运行时是否可以为空?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在运行时检测某个类型是否可以为空,以将该类型转换为相应的GraphQL类型,例如:

I'm trying to detect whether a type can be nullable or not at runtime to convert that type to the corresponding GraphQL type so that, for example:

启用了可空引用类型 :

  • string转换为String!
  • string?转换为String
  • string is converted to String!
  • string? is converted to String

可空引用类型已禁用:

  • string转换为String
  • NonNull<string>转换为String!(NonNull是自定义库类型)
  • string is converted to String
  • NonNull<string> is converted to String! (NonNull is a custom library type)

我无法适应检测到类型为空的代码:

I'm having trouble adapting the code that detected the nullability of a type:

bool isNullable = !typeInfo.IsValueType;

如何更改它,使其与启用和禁用的可为空的引用类型一起使用?

How can I change it so that it works with nullable reference types both enabled and disabled?

推荐答案

请注意,有很好的方法来检查旧的"可为空的类型,这些类型适用于在堆栈溢出中全面介绍的值类型.

Note that there are good ways to check for "the old" nullable types that applies to value types that is documented thoroughly here on Stack Overflow.

然后我将只关注可空的 reference 类型,并提供检查其中一种是否有效的方法.

I will then instead only focus on nullable reference types, and provide the means to check if one of those are in effect.

首先让我总结一下我对这个问题的评论,因为它们很重要.

Let me sum up my comments on the question first as they are rather important.

与新功能的名称相反,可空引用 types types 无关,而是与 things 有关.用于.这些事物是:

Contrary to the name of the new feature, nullable reference types is not about the types, but rather about the things these types are used for. These things are:

  • 字段
  • 属性
  • 方法返回值
  • 方法参数

现在,这当然也适用于局部变量,但是您需要一种整体的内省"来处理解码指令.我不知道这种信息是如何编码的,甚至在实际的局部变量指令中也没有编码.

Now, of course this also applies to local variables but you need a whole 'nother kind of introspection to deal with decoding instructions. I do not know how, or even if, this kind of information is encoded in the actual instructions for local variables.

好的,接下来,让我们来看一些代码(顺便说一句,我正在使用 LINQPad 使用Roslyn实验模式进行所有测试):

OK, so with that out of the way, let's look at some code (btw, I'm using LINQPad with Roslyn experimental mode to test all this):

public string? Nullable;
public string NonNullable;

这是两个公共领域.忽略这是否是一个好主意.您将如何检查这些字段的类型并检测是否存在此问号?

These are two public fields. Ignore whether this is a good idea or not. How would you check the type of these fields and detect the presence or lack of this question mark?

好吧,让我们尝试一下简单的路线:

Well, let's try the simple route:

Type nullable = GetType().GetField("Nullable").FieldType;
Type nonNullable = GetType().GetField("NonNullable").FieldType;
Console.WriteLine(ReferenceEquals(nullable, nonNullable));

运行此命令可以给我:

True

很明显,这是行不通的. Type对象是完全相同的 instance .他们不只是比较相等,我也得到了同样的东西,没有区别.基本上,FieldType会忽略此问号的存在或缺失.

So clearly this doesn't work. The Type objects are the exact same instance. They don't just compare equal, I got the same thing back, no difference. Basically, FieldType is oblivious to the presence or lack of this question mark.

我在上面的评论中包含了一些详细信息,但是主要原因是所有现有的nuget软件包,因此,编译后的代码仍可在此新支持下使用.无需重写任何代码即可突然处理NullableReferenceType<T>之类的东西. 这是一件好事,但这也意味着您仍将传递空引用,并从现有的nuget程序包中获取空引用.

My comments up above has some of those details but the main reason for this is at all existing nuget packages and compiled code will still work with this new support because of this. There is no need for any code to be rewritten to handle something like NullableReferenceType<T> suddenly. This is a good thing, but also means that you will still be passing null-references around and getting them back from existing nuget packages.

好的,那么,我们如何检测到这一点呢?答案是,如上所述,关于可空性的信息不是附加到类型上,而是附加到具有该类型的 thing 上,在本例中是字段.

OK, so then, how would we detect this? The answer is that the information about the nullability is not attached to the type, as I mentioned above, but rather to the thing that has the type, in this case the fields.

让我们在这些字段上显示属性(再次使用LINQPad):

Let's show attributes on these fields (again I'm using LINQPad):

GetType().GetField("Nullable").GetCustomAttributes().Dump();
GetType().GetField("NonNullable").GetCustomAttributes().Dump();

这给出了这个输出:

如您在此处看到的,Nullable字段具有一个附加属性NullableAttribute.我必须承认,我不知道其他属性是什么,我将不得不进行更多研究.

As you can see here, the Nullable field has an additional attribute, NullableAttribute. I must confess that I do not know what that other attribute is about, I will have to investigate more.

NullableAttribute属性比此简单示例显示的要复杂得多,因为它具有带有bool值的collection属性.让我们来看一个更复杂的示例:

This NullableAttribute attribute is much more complex than this simple example shows, as it has a collection property with bool values. Let's look at a slightly more complex example:

public List<string>? Nullable1;
public List<string?>? Nullable2;

在这里,两个字段都是对列表的可为空的引用,不同之处在于,我说过其中一个列表包含对字符串的可为空的引用,而另一个则不是.

Here, both fields are nullable references to a list, the difference is that I've said that one of the lists contains nullable references to strings, the other doesn't.

这里有一些反思,供您参考:

Here's some reflection to look at these collections:

GetType().GetField("Nullable1").GetCustomAttributesData().Dump();
GetType().GetField("Nullable2").GetCustomAttributesData().Dump();

及其输出:

在这里您可以看到该集合中的 second 元素有所不同(我已经用红色...矩形圈住了它们"),我希望第一个元素适用于列表,第二个适用于第一个泛型类型参数.如果您有包含通用类型的通用列表,则参数的数量将相应增加.

Here you can see that there is a difference on the second element in this collection (I've "circled" them with red ... rectangles ...), I expect the first element applies to the list, the second one to the first generic type parameter. If you have generic lists containing generic types, the number of parameters will increase accordingly.

您还可以在 Rico Suter的精彩博客文章.

这篇关于如何检测类型在运行时是否可以为空?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆