为什么我必须为Func参数显式指定我的类型参数?

Ale*_*i S 5 c# generics delegates functional-programming

我正在编写一个简单的Memoize帮助程序,它允许缓存方法结果,而不是每次都计算它们.但是,当我尝试传入一个方法时Memoize,编译器无法确定类型参数.从我的方法签名中不是很明显吗?有没有解决的办法?

示例代码:

using System;
using System.Collections.Concurrent;

public static class Program
{
    public static Func<T, V> Memoize<T, V>(Func<T, V> f)
    {
        var cache = new ConcurrentDictionary<T, V>();
        return a => cache.GetOrAdd(a, f);
    }

    // This is the method I wish to memoize
    public static int DoIt(string a) => a.Length;        

    static void Main()
    {
        // This line fails to compile (see later for error message)
        var cached1 = Memoize(DoIt);

        // This works, but is ugly (and doesn't scale to lots of type parameters)
        var cached2 = Memoize<string, int>(DoIt);
    }
}
Run Code Online (Sandbox Code Playgroud)

错误信息:

error CS0411: The type arguments for method 'Program.Memoize<T, V>(Func<T, V>)'
cannot be inferred from the usage. Try specifying the type arguments explicitly.
Run Code Online (Sandbox Code Playgroud)

Jon*_*eet 6

DoIt()签名不兼容Func<string, int>吗?

是的.可以将它转换为特定类型,例如:

Func<string, int> func = DoIt;
var cachedDoit = Memoize(func);
Run Code Online (Sandbox Code Playgroud)

您遇到的问题是类型推断基本上不适用于方法组转换.当您DoIt作为参数传递时,这是一个方法组.在你的情况下,它只引用一个方法,但它可以引用多个方法,具有不同的签名......这使事情变得复杂.

我经常看到这提出了LINQ,我想打电话foo.Select(SomeMethodGroup),但类型推断失败.在类型推断中对方法组有一些支持,但并不是我们想要的所有方法.

这不是C#团队懒惰的问题......类型推断非常复杂,任何变化在向后兼容性方面都充满了危险.如果你想看看它在C#5规范的第7.5.2节中 - 但坦率地说,这是我很快就迷路的规范的一部分.