0

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

  • NullabilityInfo helps to determine a reflection info objects nullability
  • NullableAttribute contains information that I can't access from code - it won't help anything
  • Nullable.GetUnderlyingType doesn't always work as expected, seems useless in this context

and this leaves me with questions:

  1. Where would I need Nullable.GetUnderlyingType, where would it work as I expect, and where else is won't?
  2. How can I determine the nullability of a generic type argument?
  3. 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.

nd_
  • 93
  • 1
  • 9
  • You cannot. `typeof(Dictionary)` and `typeof(Dictionary)` produce the same IL. Nullable reference types are kind of like Java's generics in some sense. The runtime doesn't know about them. Metadata like `NullableAttribute` are sometimes added, but not always. – Sweeper Mar 20 '23 at 03:20
  • @Sweeper Thank you! "The runtime doesn't know about them" - ok, that's what I assumed, too. This would mean, that it's more an IDE feature. and I guess it helps the compiler to match the correct overloaded target method or constructor. Anyway, I still need to know the nullability of generic arguments - there's no way around for me. – nd_ Mar 20 '23 at 03:37
  • Nullable initialization checks for reference types are a language feature, not a runtime feature, so you won't be able to figure this out through reflection. Check this reference https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/nullable-reference-types#nullable-references-and-static-analysis – Victor Ortuondo Mar 20 '23 at 13:16

0 Answers0