如何确定泛型类型参数的可空性 (NRT)?
例如,我可能有一个具有以下签名的方法:
public async Task<ViewModel?> GetPersonUri()
使用反射我想确定 Task
的类型参数是否为可为 null 的引用类型。在这种情况下,答案是肯定的。如果是:
public async Task<ViewModel> GetPersonUri()
答案应该是否定的。
如何确定泛型类型参数的可为空性?
For example, I might have a method with the following signature:
public async Task<ViewModel?> GetPersonUri()
Using reflection I would like to determine if the type parameter of Task
is a nullable reference type. In the case, the answer would be yes. If it were:
public async Task<ViewModel> GetPersonUri()
the answer should be no.
How can I determine the nullability of a generic type parameter?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
在 .NET 6 开始中,我们获得了
NullabilityInfoContext
类型,请参阅此答案< /a> 了解详细信息。在此之前,您必须自己手动检查属性。这似乎可以解决问题:
在 dotnetfiddle.net 上查看。
有关详细信息,请参阅此规范文档。
我们最终需要检查很多事情。
如果该方法的返回值具有
Nullable
属性,则其NullableFlags
字段是一个字节数组,其中数组的每个成员都引用连续的泛型类型。0
表示忽略 null,1
表示不可为 null,2
表示可为 null。因此:1
引用Task
本身,并指示它不可为空。2
引用第一个泛型类型参数,即string?
,并指示它可以为空。如果此属性不存在,我们需要检查方法本身的
NullableContext
属性。这为没有指定Nullable
属性的所有内容提供了默认的可为空性。这需要一个字节,同样是0
到2
。如果该方法没有此属性,则它可能位于包含类型或其包含类型上。继续向上寻找,直到找到(或找不到)。
稍微棘手的一点是编译器将 Nullable 和 NullableContext 属性直接发出到程序集中,这意味着每个程序集都有自己的定义。因此,我们需要使用反射来访问它们 - 我们无法将任何内容转换为
NullableAttribute
或NullableContextAttribute
。In .NET 6 onwards, we gained the
NullabilityInfoContext
type, see this answer for details.Prior to this, you have to manually inspect the attributes yourself. This seems to do the trick:
See it on dotnetfiddle.net.
See this spec doc for details.
We end up needing to check a number of things.
If the method has a
Nullable
attribute on its return value, itsNullableFlags
field is a byte array, where each member of the array refers to successive generic types. A0
means null-oblivious,1
means not nullable,2
means nullable. So in:The
1
refers to theTask<T>
itself, and indicates that it's not nullable. The2
refers to the first generic type parameter, i.e. thestring?
, and indicates that it is nullable.If this attribute doesn't exist, we need to check for a
NullableContext
attribute on the method itself. This provides a default nullability for everything which doesn't have a specifiedNullable
attribute. This takes a single byte, again0
to2
.If the method doesn't have this attribute, it might be on the containing type, or its containing type. Keep looking upwards until we find one (or not).
The slightly tricky bit is that the compiler emits the
Nullable
andNullableContext
attributes directly into the assembly, which means that each assembly will have its own definition. So we need to use reflection to access them - we can't cast anything to aNullableAttribute
orNullableContextAttribute
.