Dies scheint zu funktionieren, zumindest bei den Typen, mit denen ich es getestet habe.
Sie müssen das PropertyInfo
für die Eigenschaft übergeben, an der Sie interessiert sind, und auch das, für Type
das diese Eigenschaft definiert ist ( kein abgeleiteter oder übergeordneter Typ - es muss der genaue Typ sein):
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;
}
Weitere Informationen finden Sie in diesem Dokument .
Der allgemeine Kern ist, dass entweder die Eigenschaft selbst ein [Nullable]
Attribut haben kann, oder wenn dies nicht der Fall ist, hat der einschließende Typ möglicherweise ein [NullableContext]
Attribut. Wir suchen zuerst nach [Nullable]
, und wenn wir es nicht finden, suchen wir nach [NullableContext]
dem umschließenden Typ.
Der Compiler bettet die Attribute möglicherweise in die Assembly ein. Da wir möglicherweise einen Typ aus einer anderen Assembly betrachten, müssen wir nur Reflexionen laden.
[Nullable]
kann mit einem Array instanziiert werden, wenn die Eigenschaft generisch ist. In diesem Fall repräsentiert das erste Element die tatsächliche Eigenschaft (und weitere Elemente repräsentieren generische Argumente). [NullableContext]
wird immer mit einem einzelnen Byte instanziiert.
Ein Wert von 2
bedeutet "nullable". 1
bedeutet "nicht nullbar" und 0
bedeutet "ahnungslos".
[NullableContext(2), Nullable((byte) 0)]
den Typ (Foo
) ergänzen - das ist also, worauf zu achten ist, aber ich müsste mehr graben, um die Regeln zu verstehen, wie man das interpretiert!