Skip to content

NullabilityInfoContext reporting incorrect nullability for ParameterInfo of generic types #92487

Closed
@eiriktsarpalis

Description

@eiriktsarpalis

Description

When it comes to generic types, it is not possible for the NullabilityInfoContext class to determine the nullability of members whose type is a generic parameter -- in such cases NullabilityInfoContext will fall back to reporting the members as being Nullable. This works fine for the cases of PropertyInfo and FieldInfo, however I found a case where the nullability of a ParameterInfo is reported erroneously as NotNull.

Reproduction Steps

Type type = typeof(MyPoco<string>);
var ctx = new NullabilityInfoContext();

// Property nullability -- works as expected
PropertyInfo prop = type.GetProperties()[0];
NullabilityInfo propNullability = ctx.Create(prop);
Console.WriteLine(propNullability.ReadState); // Nullable

// Parameter nullability -- ReadState & WriteState reported as NotNull
var param = type .GetConstructors()[0].GetParameters()[0];
var info = ctx.Create(param);
Console.WriteLine(info.ReadState); // NotNull
Console.WriteLine(info.WriteState); // NotNull

public class MyPoco<T>
{
    public MyPoco(T value) => Value = value;
    public T Value { get; }
}

Expected behavior

Parameter nullability should be reported as Nullable, similar to the property.

Actual behavior

Reported as NotNull.

Regression?

No response

Known Workarounds

No response

Configuration

No response

Other information

Adding a notnull constraint makes nullability information being reported as expected:

var ctx = new NullabilityInfoContext();

Type type = typeof(MyPoco<string>);
PropertyInfo prop = type.GetProperties()[0];
NullabilityInfo propNullability = ctx.Create(prop);
Console.WriteLine(propNullability.ReadState); // NotNull

var param = typeof(MyPoco<string>).GetConstructors()[0].GetParameters()[0];
var info = ctx.Create(param);
Console.WriteLine(info.ReadState); // NotNull
Console.WriteLine(info.WriteState); // NotNull

public class MyPoco<T> where T : notnull
{
    public MyPoco(T value) => Value = value;
    public T Value { get; }
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions