Search code examples
c#.net-6.0nullable-reference-types

How to tell compiler that null can't be contained in the concurrent queue


Compiler has complaint - see code

private ConcurrentQueue<RuleContext> _queue = new ConcurrentQueue<RuleContext>();

public void Add(RuleContext ruleContext) 
{
    if (ruleContext == null) return;

    _logQueue.Enqueue(ruleContext); 
}

void Do()
{
    while (_logQueue.TryDequeue(out RuleContext ruleCtx)) // <-- converting to non-nullable type
    { ....  }
}

now, when I change that to TryDequeue(out RuleContext? ruleCtx) it calms down.

Question. If type is now RuleContext?, why in the while block I don't get a warning when dereference it like ruleCtx.HasLogMessages ??

HasLogMessages defined as

public bool HasLogMessages {get => true;}

Solution

  • out parameter of ConcurrentQueue.TryDequeue is marked with [MaybeNullWhen(false)] attribute (which does make sense because in case of false the parameter would be initialized to the default value) and RuleContext seems to be a reference type (for value types everything would be fine), hence the complaint. Just change the type to RuleContext? or var and that's it:

    void Do()
    {
        while (_logQueue.TryDequeue(out RuleContext? ruleCtx)) // or out var ruleCtx
        {
            Console.WriteLine(ruleCtx.GetType()); // no warning
        }
    }
    

    No warning inside the while block is due to the compiler being able to correctly perform static flow analysis for nullable references types in this case (hence we can be inside the while only if true is returned and the attribute warns about nulls only in case of false being returned, see the Attributes for null-state static analysis interpreted by the C# compiler article).