How to use .NET reflection to check for nullable reference type

后端 未结 2 1003
臣服心动
臣服心动 2020-11-28 10:23

C# 8.0 introduces nullable reference types. Here\'s a simple class with a nullable property:

public class Foo
{
    pu         


        
相关标签:
2条回答
  • 2020-11-28 11:05

    I wrote a library to do reflection of NRT types - internally it looks at the generated attributes and gives you a simple API:

    https://github.com/RicoSuter/Namotion.Reflection

    0 讨论(0)
  • 2020-11-28 11:07

    This appears to work, at least on the types I've tested it with.

    You need to pass the PropertyInfo for the property you're interested in.

    public static bool IsNullable(PropertyInfo property)
    {
        if (property.PropertyType.IsValueType)
            return Nullable.GetUnderlyingType(property.PropertyType) != null;
        
        var nullable = property.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;
            }
        }
    
        var context = property.DeclaringType.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.

    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] 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.

    A value of 2 means "nullable". 1 means "not nullable", and 0 means "oblivious".

    0 讨论(0)
提交回复
热议问题