ILSpy icon indicating copy to clipboard operation
ILSpy copied to clipboard

`null` of anonymous type

Open PetSerAl opened this issue 7 months ago • 5 comments

Input code

using System;

static class Program
{
    static void Main() => Test(true ? null : new { A = 1, B = 2 });

    static void Test<T>(T t) => Console.WriteLine(typeof(T).FullName);
}

Erroneous output

using System;

internal static class Program
{
	private static void Main()
	{
		Test(null);
	}

	private static void Test<T>(T t)
	{
		Console.WriteLine(typeof(T).FullName);
	}
}

error CS0411: The type arguments for method 'Program.Test<T>(T)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

Details

  • Product in use: ILSpy
  • ILSpy version: 9.1.0.7988+03b7444943e720b3134d296c0c8dd3876f8ea4ce
  • .NET version: 9.0.4+f57e6dc747158ab7ade4e62a75a6750d16b771e8

PetSerAl avatar May 10 '25 04:05 PetSerAl

I briefly investigated your issue, and the compiler simplifies the conditional expression.

https://sharplab.io/#v2:C4LglgNgNAJiDUAfAAgJgIwFgBQPnoDYACNE9AdhwG8ci6zjkAWIgWQEMwA7ACgEoiAXgB8RACoBTAM7AewAE4BXCUQD8RLoogQiIDRIDuRKkQCCQouihEAQhdREAvnwDcOWvXyMWkmQB4xYR4xImABETIATjkATwAHCQB7ADNgvgA6ADEtCAA5dgBbCVccRyA==

Since a conditional expression is the only way to target null to an anonymous type and anonymous types can't be used as explicit type parameters, we would need to detect this situation and replace null with the conditional expression.

ds5678 avatar May 10 '25 15:05 ds5678

I think this is really an edge case, not sure whether fixing this is actually worth the effort. Maybe we could just emit the anonymous type as type argument and a comment?

siegfriedpammer avatar May 10 '25 16:05 siegfriedpammer

@PetSerAl how did you encounter this issue? I can't think of any situation in which someone would write code like this.

ds5678 avatar May 10 '25 19:05 ds5678

Consider situation like that https://github.com/StephenCleary/Comparers/blob/3481de7d0a9633600599fc40be7e1af622217480/src/Nito.Comparers.Core/ComparerBuilder.cs#L23-L25 where parameter used just for type inference. But I want to be less wasteful and use just T instead of Func<T> on definition and true ? null : new { A = 1, B = 2 } instead of () => new { A = 1, B = 2 } on call site. Since first compiled into single ldnull instruction, while later require method (for delegate) and field (for instance cache).

PetSerAl avatar May 10 '25 23:05 PetSerAl

@PetSerAl Given how rare and niche your issue is, I am unlikely to work on it. If this is important to you, I would recommend you submit a pull request.

ds5678 avatar May 12 '25 02:05 ds5678