So far I've worked with Nullable.GetUnderlyingType and even NullabilityInfo.WriteState to determine the nullability of types. This worked well - sometimes.
I'd like to know the nullability of the Dictionary<string, string?> generic type arguments:
Type baseType = typeof(Dictionary<string, string?>)!;
Type[] gp = baseType.GetGenericArguments();
Assert.IsNull(Nullable.GetUnderlyingType(gp[0]));// Ok
Assert.IsNotNull(Nullable.GetUnderlyingType(gp[1]));// Fail
I can't use a NullabilityInfoContext here, because I do only have the type, but not a reflection info object available.
Now my idea was to look for the compiler attribute NullableAttribute:
string nat = "System.Runtime.CompilerServices.NullableAttribute";
Assert.IsTrue(gp[1].GetCustomAttributes(inherit: false).Any(a => a.GetType().ToString() == nat));// Ok
This does not really work, because:
Assert.IsTrue(gp[0].GetCustomAttributes(inherit: false).Any(a => a.GetType().ToString() == nat));// Ok
I can't access any information of the NullableAttribute, so it doesn't help here.
I wonder why Nullable.GetUnderlyingType returns null for the second generic argument string?? I expected the method to return typeof(string) instead.
Even when I do typeof(Dictionary<string, string?>).ToString() or or gp[1].ToString(), I don't get any nullability information in the output.
My understanding now is, that
NullabilityInfohelps to determine a reflection info objects nullabilityNullableAttributecontains information that I can't access from code - it won't help anythingNullable.GetUnderlyingTypedoesn't always work as expected, seems useless in this context
and this leaves me with questions:
- Where would I need
Nullable.GetUnderlyingType, where would it work as I expect, and where else is won't? - How can I determine the nullability of a generic type argument?
- Is nullability more an IDE feature than it does affect anything real in the CLR?
I'd really like to have a way to find out, if the author of the code that I'm inspecting with reflections did use string or string? as generic parameter, because I want to switch my own code on that condition.
Update: I tried the reflection code I found in https://stackoverflow.com/a/71585611/10797322 , too, but the NullableAttribute flags are always 0, and the NullableContextAttribute constructor parameter is always 1 - for BOTH generic type arguments.