为什么我必须明确指定Func参数的类型参数?

5
我正在编写一个简单的“记忆化”(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.

你为什么没有在问题中直接包含完整的示例呢?我认为这样会使问题更好。 - Jon Skeet
1
@AlexeiS:如果你想让代码更短,你可能可以删除System.Diagnostics导入、扩展方法以及所有使用Console的代码。(这不是关于相信编译后代码是否有效,而是关于编译器的处理。)尽管如此,它已经比许多问题要短得多了——总体上做得很好。 - Jon Skeet
1
我认为,如果问题中包含完整的示例,您就不需要链接,也可能不需要实际代码之前的片段。如果您希望我将其编辑为我认为的理想提问方式,请告诉我。 - Jon Skeet
2
我认为这个问题比那个更好,个人而言,我宁愿那个被关闭为这个的重复,而不是相反。 - Jon Skeet
1
@AlexeiS:已完成-请查看是否满意修改。 - Jon Skeet
显示剩余5条评论
1个回答

5

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

是的。将其转换为特定类型,例如:

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

你遇到的问题是类型推断在方法组转换方面并不特别有效。当你将DoIt作为参数传递时,那是一个方法组。在你的情况下,它只涉及一个方法,但它也可能涉及多个方法,具有不同的签名...而这使事情变得复杂。
我经常在LINQ中看到这种情况,我想调用foo.Select(SomeMethodGroup),但类型推断失败了。虽然有一些关于方法组的类型推断支持,但并不是我们所期望的全部内容。
这不是C#团队懒惰的问题...类型推断非常复杂,任何改变都会对向后兼容性带来巨大的危险。如果你想看的话,它在C# 5规范的7.5.2节中 - 但坦白地说,那是我很快就会迷失的规范部分。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接