I have this .NET 8.0 code that uses a Quartz.JobDataMap
and gives me weird nullability warnings. I've narrowed it down to this object construction and assignment:
//cronExpression is a non-nullable string parameter
var test1 = cronExpression; //Tooltip says "'cronExpression' is not null here."
// Set up JobDataMap with necessary parameters
var jobDataMap = new JobDataMap
{
{ "JobName", dbJob.JobName },
{ "JobType", dbJob.JobType },
{ "CronExpression", cronExpression },
{ "Id", dbJob.Id }
};
var test2 = cronExpression; //Tooltip says "'cronExpression' may be null here."
I don't understand how this is possible. What can possibly trick the compiler into thinking this local variable can become null? And what's the best way to solve it and avoid the spurious nullability warnings down the line?
I think I found the culprit: A bug in Quartz.
JobDataMap
's Add
method is misdeclared:
public virtual void Add(TKey key, [MaybeNull] TValue value)
MaybeNull
was used in place of AllowNull
, despite the documentation clearly stating it should be used for inputs, not outputs.
Specifies that an output may be null even if the corresponding type disallows it.
Guess I'll have to see how reporting bugs works...
Edit: Argh, what the decompiler shows and what the actual source code shows are different beasts. Wheras the decompiler showed me a MaybeNull
attribute, the current source code simply says public void Add(TKey key, TValue? value)
and has apparently been such for five months.
After further inquiry, it appears this bug was fixed in the source code five months ago, but the latest NuGet package I found (v3.13.1 dated 2024-Nov-2) still has it...
As evidenced by the CIL from Quartz.dll v3.13.1:
.method public hidebysig newslot virtual
instance void Add(!TKey key,
!TValue 'value') cil managed
{
.param [2]
.custom instance void [System.Runtime]System.Diagnostics.CodeAnalysis.MaybeNullAttribute::.ctor() = ( 01 00 00 00 )
Whereas the CIL for a properly declared Add(TKey, TValue?) looks like:
.method public hidebysig instance void Add(!TKey key,
!TValue 'value') cil managed
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = ( 01 00 01 00 00 )
.param [2]
.custom instance void [System.Runtime]System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = ( 01 00 02 00 00 )