当存在泛型返回值时,为什么编译器不能推断出通用参数?

时间:2015-12-11 17:15:15

标签: c# .net generics

考虑以下功能:

public void DoSomething<TSource>(TSource data)
{
   // ...
}

在C#中,编译器可以通过检查方法的参数隐式推断出TSource的类型:

DoSomething("Hello") // Works fine. DoSomething<string>("Hello") is called.

为什么我们不能在有通用返回值时这样做?

例如:

public TResult DoSomething<TResult, TSource>(TSource data)
{
    // ...
}

TResult无法推断(我理解为什么),但编译器肯定可以推断TSource的类型,可以吗?

但是,这不会编译:

int result = DoSomething<int>("Hello"); // This should call DoSomething<int,string>("Hello")

1 个答案:

答案 0 :(得分:3)

这不是编译器的问题 - C#要求您明确指定所有类型参数或让它推断所有类型参数。

使用您尝试过的语法没有中间立场,我想是因为如果你有这样的通用方法:

public void DoSomething<T1, T2>(T1 data, T2 data)
{
    // ...
}

你用它就是这样:

var obj1 = "Hello!";
var obj2 = "Hello?";
DoSomething<IEnumerable<char>>(obj1, obj2);

最后一行可以是两个同样有效的东西的简写:

DoSomething<string, IEnumerable<char>>(obj1, obj2);
DoSomething<IEnumerable<char>, string>(obj1, obj2);

必须采用不同的语法(如<string, ?>)或其他推理规则,以使像这样的案例有意义且不含糊不清。我想设计团队认为它不值得。

请注意,如果您确实需要部分泛型类型推断,则有一种将调用拆分为两个调用的常见模式,其中一个辅助对象用于保存调用之间的信息。这基本上是currying,适用于类型参数。

我将以使用公共接口和私有实现的形式呈现模式,但如果您不关心这一点,则可以完全跳过该接口。

public TResult DoSomething<TResult, TSource>(TSource data)
{
    // ...
}

会变成:

public IWrapper<TSource> DoSomething<TSource>(TSource data)
{
    return new WrapperImplementation<TSource>(data);
}

其中:

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>()
    {
        // ...
    }
}

用法是:

DoSomething("Hello").Apply<int>();