如何使用 .NET 反射检查可空引用类型 [英] How to use .NET reflection to check for nullable reference type

查看:23
本文介绍了如何使用 .NET 反射检查可空引用类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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屋!

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