【问题标题】:Type Inference for delegate parameters to methods方法的委托参数的类型推断
【发布时间】:2016-03-31 21:45:38
【问题描述】:

我一直在玩 C# 中的类型推断,我读过 this thread。如线程中所述,类型推断不适用于泛型委托(当您将方法传递给此委托参数而没有任何显式转换时),如 Func、Action 等。然后我想尝试使用 .net Func 的 SelectMany 等 LINQ 运算符类而不是 lambda 表达式以查看结果。然而,这不是我预期的结果。

我创建了一个名为 L1 的测试类,其中包含一个字符串列表,以便在 SelectMany 中使用(展平)。除此之外,我创建了一个测试方法来传递而不是 Func 类型参数。

public class L1
{
    private L1() {}

    public L1(string m)
    {
        Isim = m;
        numbers = new List<string> { "1", "2", "3", "4", "5" };
    }

    public List<string> numbers; 
    public string Isim { get; private set; }
}
private static IEnumerable<int> a(L1 k)
{
    return Enumerable.Empty<int>();
}

当我创建如下扩展方法时,C# 编译器无法推断泛型参数的类型。

public static void Test<T1, T2>(this L1 l, Func<T1, IEnumerable<T2>> a)
{
}

(new L1("test")).Test(a);

它给出了'错误 CS0411:方法'EnumSand.Test(L1, Func>)' 的类型参数不能从用法中推断出来。尝试明确指定类型参数。'正如我所解释的那样。

但是,当我在 LINQ SelectMany 扩展方法中使用此方法 a 时,编译器不会给出任何错误并且可以正常工作。

L1[] l1 = new L1[5] {
                        new L1("one"), new L1("two"), 
                        new L1("three"), new L1("four"), 
                        new L1("five")
                    };

var slack = l1.SelectMany(a);

foreach (var t in slack)
{
    Console.WriteLine(t);
}

那么,这些案例之间有什么区别,以及如何在 SelectMany 中进行良好的类型推断?

【问题讨论】:

    标签: c# .net linq generics type-inference


    【解决方案1】:

    问题出在这里:

    public static void Test<T1, T2>(this L1 l, Func<T1, IEnumerable<T2>> a)
    

    T2 绑定到 intT1 可能是任何东西,这就是它无法推断的原因。

    您可以将第二个参数更改为Func&lt;L1, IEnmuerable&lt;T2&gt;&gt; 并完全删除T1 或将this L1 更改为this T1

    编辑: 当您有以下方法时,请考虑情况:

    private static IEnumerable<int> a(L1 k)
    {
        return Enumerable.Empty<int>();
    }
    
    private static IEnumerable<int> a(string k)
    {
        return Enumerable.Empty<int>();
    }
    

    您现在能说(new L1("test")).Test(a); 使用应该使用哪个a 方法吗?

    【讨论】:

    • 你的意思是编译器可以从返回类型中获取,但不能从参数中获取? Func&lt;TSource, IEnumerable&lt;TResult&gt;&gt; selector in SelectMany 签名由于扩展方法规则已经知道TSource,在这种情况下返回类型推断就足够了吗?
    • @Deniz,我同意这个答案。这并不意味着编译器可以从返回类型推断,但不能从参数推断。不确定,为什么你会这么想。
    • @AndrewSavinykh,我尝试将 T1 更改为 L1,结果相同。
    • @Deniz,将 T1 更改为 L1 有效。仔细检查您的代码。你一定是搞错了。
    • @Deniz,这绝对有效:public static void Test&lt;T1, T2&gt;(this T1 l, Func&lt;T1, IEnumerable&lt;T2&gt;&gt; a)。您在原始问题中链接的主题解释了为什么仔细阅读它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-20
    • 1970-01-01
    • 2010-12-31
    相关资源
    最近更新 更多