I don't understand why C# doesn't infer a type in the following complete situation:
public interface IThing {}
public class Thing1 : IThing {}
public class Thing2 : IThing {}
public interface IContainer {}
public class Container1 : IContainer
{
public IThing A { get { return new Thing1(); } }
public IThing B { get { return new Thing2(); } }
}
public class Container2 : IContainer
{
public IThing C { get { return new Thing1(); } }
public IThing D { get { return new Thing2(); } }
}
public class SomeClass
{
public void PerformTask() {}
}
public static class ExtensionMethods
{
// This function behaves as I would expect, inferring TContainer
public static TContainer DoStuffWithThings<TContainer>(this TContainer container, Func<TContainer, IThing> getSomething, Func<TContainer, IThing> getSomethingElse)
where TContainer : IContainer
{
var something = getSomething.Invoke(container);
var somethingElse = getSomethingElse.Invoke(container);
// something and something else are the things we specify in our lambda expressions with respect to the container
return container;
}
// The method in question
public static TCustomReturnType DoStuffWithThings<TContainer, TCustomReturnType>(this TContainer container, Func<TContainer, IThing> getSomething, Func<TContainer, IThing> getSomethingElse)
where TContainer : IContainer
where TCustomReturnType : new()
{
var something = getSomething.Invoke(container);
var somethingElse = getSomethingElse.Invoke(container);
// Do stuff with the things just as above
// This time we return our custom type
return new TCustomReturnType();
}
}
public class Driver
{
public static void Main(string[] args)
{
var container1 = new Container1();
var container2 = new Container2();
// I can do stuff with the things for each container, returning the container each time.
container1.DoStuffWithThings(c => c.A, c => c.B)
.DoStuffWithThings(c => c.B, c => c.A);
container2.DoStuffWithThings(c => c.C, c => c.D)
.DoStuffWithThings(c => c.D, c => c.C);
// Now we try to do the same but with the custom return type
container1.DoStuffWithThings<Container1, SomeClass>(c => c.A, c => c.B)
.PerformTask();
// As you can see, the compiler requires us to specify Container1 as the container type.
// Why is it not inferred? It is called from an instance of Container1.
// The behavior I expect is for container1.DoStuffWithThings<SomeClass>(...) to infer
// the container type and return a new instance of SomeClass.
}
}
The basic idea is that when there is only one generic type parameter, the compiler infers the type. When I add a second, the compiler doesn't infer either (It obviously can't infer the second, but I'm not sure why it can't infer the first). My question is why is the type of the container not inferred?
The reason is that the second type parameter it's not used in any of the function parameters. So there is no way it's type can be inferred purely from parameter usage.
If you were to have a method signature like this (obviously not equivalent to your code, just an example):
public static TResult DoStuffWithThings<TContainer, TResult>(
this TContainer container,
Func<TContainer, TResult> getSomething)
Then it would be able to infer the generic types from the parameters.
If you want to avoid specifying the first parameter you can split the method up into two functions and hide intermediate parameters in a generic type, like this:
public static IntermediateResult<T> DoStuffWithThings<T>(this T container)
public class IntermediateResult<T>
{
public WithReturnType<TResult>()
}
Then it calling as
var result = container.DoStuffWithThings().WithReturnType<Result>();
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