【问题标题】:Why do I have to explicitly specify my type arguments for Func parameters?为什么我必须为 Func 参数显式指定我的类型参数?
【发布时间】:2018-09-01 22:03:26
【问题描述】:

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

【问题讨论】:

  • 您没有直接在问题中包含完整示例的任何原因?这会让问题变得更好,IMO。
  • @AlexeiS:如果你想让它更短,你可以删除System.Diagnostics 导入和扩展方法,以及所有使用Console 的代码。 (这不是关于相信代码在编译后可以工作,而是关于编译器的处理。)不过,它已经比许多问题短得多了——总的来说做得很好。
  • (我还要说,对于问题中的完整示例,您不需要链接,并且在实际代码之前您可能不需要它的 sn-ps。如果您'希望我将其编辑成我认为提出问题的理想方式,让我知道。)
  • (我个人认为这是一个比那个更好的问题 - 我宁愿将一个作为副本关闭而不是反之亦然。)
  • @AlexeiS:完成 - 看看您是否对更改感到满意。

标签: c# generics functional-programming delegates


【解决方案1】:

DoIt()签名不兼容Func&lt;string, int&gt;吗?

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

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

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

我经常看到这与 LINQ 一起出现,我想在其中调用 foo.Select(SomeMethodGroup),但类型推断失败。 一些支持类型推断中的方法组,但这并不是我们想要的一切。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-05-23
    • 2021-12-31
    • 2012-09-27
    • 1970-01-01
    • 2019-02-19
    • 1970-01-01
    相关资源
    最近更新 更多