我正在编写一个简单的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.
答案 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节中 - 但坦率地说,这是我很快就迷路的规范的一部分。