【问题标题】:How do I use the ValueTuple naming feature with anonymous methods?如何将 ValueTuple 命名功能与匿名方法一起使用?
【发布时间】:2018-10-08 21:51:29
【问题描述】:

我想使用ValueTuple的命名功能如下:

     IEnumerable<(string, char, int)> valueTuples = new(string, char, int)[]
     {
        ("First", '1', 1),
        ("Second", '2', 2),
        ("Third", '3', 3)
     };

     var projection1 = valueTuples.Select(((string s, char c, int i) tuple) => tuple.i);

但它不会编译并带有不是很有帮助的错误消息。然而,这些都编译:

     var projection2 = valueTuples.Select(tuple => tuple.Item1);

     var projection3 = valueTuples.Select(((string, char, int) tuple) => tuple.Item1);

尝试更直接的方法,这不会编译但会出错 更有帮助的消息:

     var projection4 = Enumerable.Select(
        valueTuples, ((string s, char c, int i) tuple) => tuple.i);

这导致尝试这个,编译:

     var projection5 = Enumerable.Select<(string, char, int), int>(
        valueTuples, ((string s, char c, int i) tuple) => tuple.i);

最终激发了这一点,编译:

     var projection6 = valueTuples.Select<(string, char, int), int>(
        ((string s, char c, int i) tuple) => tuple.i);

这是 IEnumerable 扩展方法的普遍问题吗? 看起来不是因为这样编译:

     var filtered = valueTuples.Where(((string s, char c, int i) tuple) => tuple.i > 1);

为什么我必须求助于 projection6 语法才能让它工作?

【问题讨论】:

    标签: c# ienumerable anonymous-methods valuetuple


    【解决方案1】:

    你有一个未命名的元组列表(string, char, int)(注意没有名字)。出于这个原因,使用默认名称Item1Item2 等可以正常访问。

    但是,您传递给Select lamdba 的内容被命名为元组类型:

    (string s, char c, int i) tuple) => tuple.i
    

    类型推断似乎并不认为命名元组和未命名元组(或两个具有不同名称的命名元组)完全相同,并且在使用这种“不同”类型的某些情况下,推断会失败。我不完全确定为什么,也许它甚至是一个错误,或者规范中的某些内容涵盖了这一点。

    但是,有了这些知识,我们可以发现解决问题的最佳方法是从一开始就使用命名元组类型:

    IEnumerable<(string s, char c, int i)> valueTuples = new[] {
        ("First", '1', 1),
        ("Second", '2', 2),
        ("Third", '3', 3)
    };            
    var projection1 = valueTuples.Select(tuple => tuple.i);
    

    更新:我实际上在 Roslyn 存储库中找到了一个关于此的 issue。这确实是一个已确认的错误,甚至已经解决了。没有关于这个错误的性质的解释。修复应该出现在 15.7 版本中。

    即使进行了修复,我仍然认为从一开始就使用命名元组是最好的方法。然后你不需要在每个 lambda 中一次又一次地指定名称(这些名称甚至可以不同,这使得整个事情更加混乱)。

    【讨论】:

    • 还值得注意的是,这并不是 IEnumerable、Linq 或扩展方法的具体问题,仅使用简单的泛型方法即可轻松重现。关于类型推断的 C# 语言规范可以在这里找到:docs.microsoft.com/en-us/dotnet/csharp/language-reference/…
    • 好的,谢谢。我错过了那个简单的解决方案——也许是因为我的实际 IEnumerable 是从另一种方法返回的。但是我可以访问该方法,并且可以在返回签名中给出 ValueTuple 名称,并且可以正常工作。我开始喜欢 ValueTuples。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-17
    • 1970-01-01
    • 2022-07-29
    • 1970-01-01
    • 1970-01-01
    • 2012-03-05
    相关资源
    最近更新 更多