如何使用 .NET 反射检查可空引用类型 [英] How to use .NET reflection to check for nullable reference type
问题描述
C# 8.0 引入了可为空的引用类型.这是一个具有可为空属性的简单类:
C# 8.0 introduces nullable reference types. Here's a simple class with a nullable property:
public class Foo
{
public String? Bar { get; set; }
}
有没有办法通过反射检查类属性是否使用可为空的引用类型?
Is there a way to check a class property uses a nullable reference type via reflection?
推荐答案
这似乎有效,至少在我测试过的类型上如此.
This appears to work, at least on the types I've tested it with.
public static bool IsNullable(PropertyInfo property) =>
IsNullableHelper(property.PropertyType, property.DeclaringType, property.CustomAttributes);
public static bool IsNullable(FieldInfo field) =>
IsNullableHelper(field.FieldType, field.DeclaringType, field.CustomAttributes);
public static bool IsNullable(ParameterInfo parameter) =>
IsNullableHelper(parameter.ParameterType, parameter.Member, parameter.CustomAttributes);
private static bool IsNullableHelper(Type memberType, MemberInfo? declaringType, IEnumerable<CustomAttributeData> customAttributes)
{
if (memberType.IsValueType)
return Nullable.GetUnderlyingType(memberType) != null;
var nullable = customAttributes
.FirstOrDefault(x => x.AttributeType.FullName == "System.Runtime.CompilerServices.NullableAttribute");
if (nullable != null && nullable.ConstructorArguments.Count == 1)
{
var attributeArgument = nullable.ConstructorArguments[0];
if (attributeArgument.ArgumentType == typeof(byte[]))
{
var args = (ReadOnlyCollection<CustomAttributeTypedArgument>)attributeArgument.Value!;
if (args.Count > 0 && args[0].ArgumentType == typeof(byte))
{
return (byte)args[0].Value! == 2;
}
}
else if (attributeArgument.ArgumentType == typeof(byte))
{
return (byte)attributeArgument.Value! == 2;
}
}
for (var type = declaringType; type != null; type = type.DeclaringType)
{
var context = type.CustomAttributes
.FirstOrDefault(x => x.AttributeType.FullName == "System.Runtime.CompilerServices.NullableContextAttribute");
if (context != null &&
context.ConstructorArguments.Count == 1 &&
context.ConstructorArguments[0].ArgumentType == typeof(byte))
{
return (byte)context.ConstructorArguments[0].Value! == 2;
}
}
// Couldn't find a suitable attribute
return false;
}
有关详细信息,请参阅本文档.
See this document for details.
一般要点是属性本身可以有一个 [Nullable]
属性,或者如果它没有,封闭类型可能有 [NullableContext]
属性.我们首先寻找[Nullable]
,如果没有找到,就在封闭类型上寻找[NullableContext]
.
The general gist is that either the property itself can have a [Nullable]
attribute on it, or if it doesn't the enclosing type might have [NullableContext]
attribute. We first look for [Nullable]
, then if we don't find it we look for [NullableContext]
on the enclosing type.
编译器可能会将属性嵌入到程序集中,并且由于我们可能正在查看来自不同程序集的类型,因此我们需要执行仅反射加载.
The compiler might embed the attributes into the assembly, and since we might be looking at a type from a different assembly, we need to do a reflection-only load.
[Nullable]
可以用数组实例化,如果属性是通用的.在这种情况下,第一个元素代表实际属性(其他元素代表通用参数).[NullableContext]
总是用单个字节实例化.
[Nullable]
might be instantiated with an array, if the property is generic. In this case, the first element represents the actual property (and further elements represent generic arguments). [NullableContext]
is always instantiated with a single byte.
2
的值意味着可空".1
表示不可为空",0
表示遗忘".
A value of 2
means "nullable". 1
means "not nullable", and 0
means "oblivious".
这篇关于如何使用 .NET 反射检查可空引用类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!