Wygląda na to, że działa, przynajmniej na typach, z którymi go testowałem.
Musisz podać PropertyInfo
właściwość, która Cię interesuje, a także właściwość, dla Type
której ta właściwość jest zdefiniowana ( nie typ pochodny ani nadrzędny - musi to być typ dokładny):
public static bool IsNullable(Type enclosingType, PropertyInfo property)
{
if (!enclosingType.GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly).Contains(property))
throw new ArgumentException("enclosingType must be the type which defines property");
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 = enclosingType.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;
}
Szczegółowe informacje można znaleźć w tym dokumencie .
Ogólną zasadą jest to, że albo sama właściwość może mieć [Nullable]
atrybut, albo jeśli nie, typ otaczający może mieć [NullableContext]
atrybut. Najpierw szukamy [Nullable]
, a następnie, jeśli go nie znajdziemy, szukamy [NullableContext]
na podstawie typu zamykającego.
Kompilator może osadzić atrybuty w zestawie, a ponieważ możemy patrzeć na typ z innego zestawu, musimy wykonać ładowanie tylko do odbicia.
[Nullable]
może być utworzony za pomocą tablicy, jeśli właściwość jest ogólna. W tym przypadku pierwszy element reprezentuje rzeczywistą właściwość (a kolejne elementy reprezentują ogólne argumenty). [NullableContext]
jest zawsze tworzony z pojedynczym bajtem.
Wartość 2
oznacza „nullable”. 1
oznacza „nie dopuszczać do wartości zerowej” i 0
oznacza „nieświadomy”.
[NullableContext(2), Nullable((byte) 0)]
to do type (Foo
) - więc to jest to, co należy sprawdzić, ale musiałbym wykopać więcej, aby zrozumieć zasady interpretowania tego!