6

There are a lot of examples of string properties with "nullable" vs "non-nullable" declarations:

public MyClass {
    public string NotNullable {get;set;}
    public string? Nullable {get;set;}
}

This is even shown in the Microsoft C# official documentation on nullables as the primary example of nullable types.

This is made confusing by the fact that strings in C# can be null by default.

string myString = null; //100% valid, compile-able code

I have a script where I'm checking the types of properties in a class, to see if they are nullable. It's a long story why, but these nullable flags are put in a list and exported.

bool nullable = false;
if (classProperty.PropertyType.IsGenericType 
   && classProperty.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
    nullable = true;
}

This works for int?s, class references, DateTime? objects, basically anything other than string?, it can determine if it's an explicitly-declared nullable property or not.

Is there any way to determine if a property is string versus string?, and if not, why have (and laud in the documentation) a nullable string type for C#?


Also tried

An alternate method, comparing the PropertyType to a type derived directly:

modelProperty.PropertyType == typeof(int) //works
modelProperty.PropertyType == typeof(int?) //works
modelProperty.PropertyType == typeof(double) //works
modelProperty.PropertyType == typeof(double?) //works
modelProperty.PropertyType == typeof(string) //works
modelProperty.PropertyType == typeof(string?) //NOPE!

C# vomits an error about not being able to use the typeof operator on a nullable type when passed string? despite having literally just done so without issue for int? and double?. Also, modelProperty == typeof(string) is true whether the property was declared with either string or string?.

Guru Stron
  • 102,774
  • 10
  • 95
  • 132
Randy Hall
  • 7,716
  • 16
  • 73
  • 151
  • 2
    Not a full answer, but int is a value type. DateTime is a struct. string is special, it's a reference type to an immutable value. You also can't have a nullable class reference, like `public Nullable myClass {get;set;}`. The ? syntax works differently for value types and reference types. – Robert McKee Jan 28 '22 at 23:02
  • 1
    After looking into the IL code a little, it appears that the compiler doesn't interpret `string?` as a `Nullable`, but rather it treats it as a normal `string` with a `NullableAttribute` on the property/field and a `NullableContextAttribute` on the getter and setter. Both attributes take a parameter of `2` which signifies nullable. `1` would signify non-nullable. – Jesse Jan 28 '22 at 23:08

1 Answers1

4

@Jesse got me pointed in the right direction. If anyone comes looking later, this is how I ended up checking and it seems to be working across the board:

if(modelProperty.PropertyType == typeof(string)
&& modelProperty.GetMethod?.CustomAttributes.Where(x => x.AttributeType.Name == "NullableContextAttribute").Count() == 0){
    nullable = true;
}

Still glad to entertain any more succinct answers!

Randy Hall
  • 7,716
  • 16
  • 73
  • 151