3

I have the following method which takes a Type as a parameter and checks if it is IEnumerable<T>. If it is, it returns true and sets the type of T in an out variable, otherwise it returns false.

private static bool TryGetEnumeratedType(Type type, [NotNullWhen(true)] out Type? enumeratedType)
{
    enumeratedType = null;
    bool isEnumerable = type.GetInterfaces().Any(i => i.GetTypeInfo() == typeof(IEnumerable));

    if (!isEnumerable)
    {
        return false;
    }

    Type? genericType = type.GetGenericArguments().FirstOrDefault();

    if (genericType is null)
    {
        return false;
    }

    enumeratedType = genericType;

    return true;
}

If I call the method this way, there is no issue:

Type fieldType;

if (TryGetEnumeratedType(inType, out Type? type))
{
    fieldType = type;
}
else
{
    fieldType = inType;
}

But if I assign the result to a variable and check against the variable, I get a compiler warning when assigning fieldType = type saying that type may be null.

Type fieldType;
bool isEnumerable = TryGetEnumeratedType(inType, out Type? type);

if (isEnumerable)
{
    fieldType = type;
}
else
{
    fieldType = inType;
}

Is this a bug, or am I missing something?

Valuator
  • 3,262
  • 2
  • 29
  • 53

1 Answers1

1

I believe that has nothing to do with NotNullWhen. The compiler just doesn't do that kind of work - it doesn't go into deep checks of "where did that variable come from". Doing that would probably be 1) hard to implement and 2) you wouldn't know where to stop: how high up the call stack should compiler go to ensure there is no null assigned to your value? That would probably be very resource-intensive. This answer discusses it a bit.

Consider these two methods, for example:

public int GetInt() //no warning
{
    if (true)
        return 1; 
}

public int GetAnotherInt() //CS0161: not all code paths return a value
{
    var @true = true;
    if (@true)
        return 1; 
}
defaultUsernameN
  • 365
  • 5
  • 14