2013-03-16 122 views
4

我不明白为什么C#不下面的完整情况推断类型:多个泛型类型的类型推断参数

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. 
    } 
} 

的基本思想是,当只有一个泛型类型参数,编译器推断该类型。当我添加第二个时,编译器不会推断(它显然不能推断第二个,但我不知道为什么它不能推断第一个)。我的问题是为什么不推断容器的类型?

回答

7

原因是第二个类型参数没有在任何函数参数中使用。因此,它的类型可以纯粹从参数的使用中推断出来。

如果你有这样的方法签名(显然不等同于你的代码,只是一个例子):

public static TResult DoStuffWithThings<TContainer, TResult>(
    this TContainer container, 
    Func<TContainer, TResult> getSomething) 

然后能够从参数推断泛型类型。

如果要避免指定所述第一参数可在一个通用型分裂方法成两个功能和隐藏中间参数,如下所示:

public static IntermediateResult<T> DoStuffWithThings<T>(this T container) 

public class IntermediateResult<T> 
{ 
    public WithReturnType<TResult>() 
} 

然后它调用作为

var result = container.DoStuffWithThings().WithReturnType<Result>(); 
+0

我不希望编译器推断第二个参数(如您所说,它不用于任何参数)。但我确实希望它能推断出第一个参数(这在参数中)。所以我可以调用container1.DoStuffWithThings (...)并推断出TContainer是Container1。进行类型推断时,参数是全部还是全无处理? – perrick 2013-03-16 02:57:35

+1

您必须指定* all * type参数或* none *,但请参阅我更新后的答案。 – 2013-03-16 03:05:39

+0

谢谢。我没有意识到这是全部或没有。对于后人,我会好奇的想知道为什么;只推断已知类型和指定未知类型的设计会在哪里崩溃? – perrick 2013-03-16 03:22:25