【问题标题】:Why can't the compiler infer a generic parameter when there is a generic return value? [duplicate]为什么当有泛型返回值时编译器不能推断出泛型参数? [复制]
【发布时间】:2016-03-17 16:29:00
【问题描述】:

考虑以下函数:

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")

【问题讨论】:

标签: c# .net generics


【解决方案1】:

这不是编译器的问题 - 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);

必须采用不同的语法(如&lt;string, ?&gt;)或额外的推理规则,以使此类案例有意义且明确。我想设计团队认为这不值得。


请注意,如果您真的想要部分泛型类型推断,有一种常见的模式是将调用拆分为两个调用,并使用辅助对象来保存调用之间的信息。这本质上是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>();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-27
    • 2013-10-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-15
    • 2021-03-11
    相关资源
    最近更新 更多