4

I have this code:

public T? Foo<T>()
    where T : class?
{
    return null;
}

It gives an error that is logical and expected:

A nullable type parameter must be known to be a value type or non-nullable reference type. Consider adding a 'class', 'struct', or type constraint.

Now I add one more constraint:

public T? Foo<T>()
    where T : class?, IDisposable // Could be any interface I guess
{
    return null;
}

Now interestingly enough error has just disappeared. Though it really seems to me we have conflicting constraints since interface is non-nullalbe while class? is.

Am I missing something here or is there a trouble with compiler?

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
Ilya Chernomordik
  • 27,817
  • 27
  • 121
  • 207

1 Answers1

5

The generic type constraint where T : IDisposable means "T must be non-nullable and must implement IDisposable". Where you have multiple generic type constraints of differing nullabilities, the constraint overall is only nullable if all constraints are nullable.

So the fact that class? is nullable gets overridden by the fact that IDisposable is not.

You need where T : class?, IDisposable?.

canton7
  • 37,633
  • 3
  • 64
  • 77
  • Thanks for the answer, it seems it works this way, but it's kind of not obvious really and somewhat confusing. I have additionally tried to return nullable whith such a constraint, but that does not work: https://stackoverflow.com/questions/59631460/c-sharp-8-gives-a-warning-when-returning-a-nullable-generic-with-nullable-constr – Ilya Chernomordik Jan 07 '20 at 15:34
  • Agreed, I find it non-obvious and confusing as well. And easily forgotten! – canton7 Jan 07 '20 at 15:35