简体   繁体   English

使用多个泛型类型参数键入推断

[英]Type inference with multiple generic type parameters

I don't understand why C# doesn't infer a type in the following complete situation: 我不明白为什么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.
    }
}

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>();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM