Why can't nested generic types be inferred?
Asked Answered
D

1

16

Given the following classes...

public abstract class FooBase<TBar> where TBar : BarBase{}
public abstract class BarBase{}
public class Bar1 : BarBase{}
public class Foo1 : FooBase<Bar1> {}

...and the following method...

public TBar DoSomething<TFoo, TBar>(TFoo theFoo)
    where TFoo : FooBase<TBar>
    where TBar : BarBase
{
    return default(TBar);
}

Why can't the following line of code imply the return type?

Bar1 myBar = DoSomething(new Foo1());

Instead I have to specify the generic types like this...

Bar1 myBar = DoSomething<Foo1, Bar1>(new Foo1());
Dorcia answered 8/7, 2011 at 21:26 Comment(0)
C
23

Method type inference ignores generic constraints on the method type parameters (*). Method type inference reasons only about deductions that can be made by comparing arguments to formal parameter types. Since the only generic type parameter that appears in your formal parameter types is TFoo, there is no way to deduce TBar.

Many people believe this design decision to be wrong, wrong, wrong. Though I take their point, this decision does lead to what are in my opinion some nice properties. For an extended debate on this issue, see the bazillion or so comments on this blog article telling me that I am wrong, wrong, wrong:

http://blogs.msdn.com/b/ericlippert/archive/2009/12/10/constraints-are-not-part-of-the-signature.aspx


(*) Note that I said constraints on method type parameters are ignored, not constraints in general. If the deduced formal parameter types are constructed generic types such that the construction violates their type parameter constraints then this fact causes type inference to fail and the method is not a candidate for overload resolution. But under no circumstances do we make a deduction from a constraint other than "Hmm, clearly this is not going to work".

Counterfeit answered 8/7, 2011 at 21:33 Comment(1)
I think some people will wonder why we wouldn't try to use the constraint to infer the type. Another way to think about this, is if you consider first we must determine what concrete types are being used for TFoo and TBar, then any code referencing those types now uses the concrete type. In the case of FooBase<TBar>, here we are saying after you know what type TBar is, then FooBase<TBar> will become FeeBase<ActualType>. This constraint can't be used as part of type inference, because we don't know the type until inference completes. It'd be circular logic.Malcolmmalcom

© 2022 - 2024 — McMap. All rights reserved.