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

时间:2018-03-23 09:17:35

标签: c# generics functional-programming delegates

我正在编写一个简单的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);
    }
}

错误讯息:

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.

1 个答案:

答案 0 :(得分:6)

  

是否DoIt()签名与Func<string, int>兼容?

是的。将它转换为特定类型是很好的,例如:

Func<string, int> func = DoIt;
var cachedDoit = Memoize(func);

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

我经常看到这是LINQ,我想调用foo.Select(SomeMethodGroup),但类型推断失败。对类型推断中的方法组有某些支持,但它并不是我们想要的所有内容。

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