For example, I might have a method with the following signature:
public async Task<ViewModel?> GetPersonUri()
Using reflection I would like to determine if the type parameter of Task is a nullable reference type. In the case, the answer would be yes. If it were:
public async Task<ViewModel> GetPersonUri()
the answer should be no.
How can I determine the nullability of a generic type parameter?
In .NET 6 onwards, we gained the
NullabilityInfoContexttype, see this answer for details.Prior to this, you have to manually inspect the attributes yourself. This seems to do the trick:
See it on dotnetfiddle.net.
See this spec doc for details.
We end up needing to check a number of things.
If the method has a
Nullableattribute on its return value, itsNullableFlagsfield is a byte array, where each member of the array refers to successive generic types. A0means null-oblivious,1means not nullable,2means nullable. So in:The
1refers to theTask<T>itself, and indicates that it's not nullable. The2refers to the first generic type parameter, i.e. thestring?, and indicates that it is nullable.If this attribute doesn't exist, we need to check for a
NullableContextattribute on the method itself. This provides a default nullability for everything which doesn't have a specifiedNullableattribute. This takes a single byte, again0to2.If the method doesn't have this attribute, it might be on the containing type, or its containing type. Keep looking upwards until we find one (or not).
The slightly tricky bit is that the compiler emits the
NullableandNullableContextattributes directly into the assembly, which means that each assembly will have its own definition. So we need to use reflection to access them - we can't cast anything to aNullableAttributeorNullableContextAttribute.