Consider this MCVE:
using System;
public interface IThing { }
public class Foo : IThing
{
public static Foo Create() => new Foo();
}
public class Bar : IThing
{
public static Bar Create() => new Bar();
}
public delegate IThing ThingCreator();
class Program
{
static void Test(ThingCreator creator)
{
Console.WriteLine(creator.Method.ReturnType);
}
static void Main()
{
Test(Foo.Create); // Prints: Foo
Test(Bar.Create); // Prints: Bar
Test(() => new Foo()); // Prints: IThing
Test(() => new Bar()); // Prints: IThing
}
}
Why does reflecting the return type for the static factory method give the concrete type, while calling the constructor inline gives the interface? I would expect them to both be the same.
Also, is there a way to specify in the lambda version that I want the return value to be the concrete type? Or is calling a static method the only way to do that?
The return type of a lambda expression is not inferred from what the lambda acutally returns, but from the type it is assigend to. I.e., you can not assign a lambda like this (except when generic type parameters are involed; see comments of Eric Lippert):
// This generates the compiler error:
// "Cannot assign lambda expression to an implicitly-typed variable".
var lambda = () => new Foo();
You must always do something like this (lambdas are always assigned to a delegate type):
Func<MyType> lambda = () => new Foo();
Therefore in Test(() => new Foo());
the return type of the lambda is determined from the type of the parameter it is assigned to (IThing
, the return type of ThingCreator
).
In Test(Foo.Create);
you don't have a lambda at all, but a method declared as public static Foo Create() ...
. Here the type is specified explicitly and is Foo
(it makes no difference whether it is a static or instance method).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With