It's not a matter of compiler - it's that C# requires that you either explicitly specify all the type arguments or let it infer all of them.
There is no middle ground using the syntax you've attempted, and I imagine it's because if you had a generic method like this:
public void DoSomething<T1, T2>(T1 data, T2 data)
{
// ...
}
And you used it like this:
var obj1 = "Hello!";
var obj2 = "Hello?";
DoSomething<IEnumerable<char>>(obj1, obj2);
The last line could be shorthand for two equally valid things:
DoSomething<string, IEnumerable<char>>(obj1, obj2);
DoSomething<IEnumerable<char>, string>(obj1, obj2);
A different syntax (like <string, ?>
) or additional inference rules would have to be put in place to make cases like this meaningful and non-ambiguous. I imagine the design team thought that it wasn't worth it.
Note that if you really want partial generic type inference, there is a common pattern of splitting the call into two calls, with a helper object to hold the information between the calls. This is essentially currying, applied to type parameters.
I'll present the pattern in a form that uses a public interface and an private implementation but if you're not concerned about that, you can skip the interface altogether.
public TResult DoSomething<TResult, TSource>(TSource data)
{
// ...
}
Would become:
public IWrapper<TSource> DoSomething<TSource>(TSource data)
{
return new WrapperImplementation<TSource>(data);
}
Where:
public interface IWrapper<T>
{
TResult Apply<TResult>();
}
class WrapperImplementation<T> : IWrapper<T>
{
private readonly T _source;
public WrapperImplementation(T source)
{
_source = source;
}
public TResult Apply<TResult>()
{
// ...
}
}
The usage is:
DoSomething("Hello").Apply<int>();