【问题标题】:Linq to Objects and Anonymous TypesLinq to 对象和匿名类型
【发布时间】:2010-07-07 20:47:55
【问题描述】:

我是 Linq to Objects 的新手,刚刚遇到匿名类型和范围的问题。

例如,这很好用:

    Public Sub CreateResults()
        results = From e In CustomerList
                  Join f In OrderList On CustomerList.ID Equals OrderList.ID
                  Select New With {e.FirstName, e.LastName, f.OrderID}

        For Each r in results
            Console.Writeline(r.FirstName, r.LastName, r.OrderID)
        Next t
    End Sub

但这不是:

Public Class Foo

    Private _linqResults 

    Public Sub CreateResults()
        _linqResults = From e In CustomerList
                       Join f In OrderList On CustomerList.ID Equals OrderList.ID
                       Select New With {e.FirstName, e.LastName, f.OrderID}
    End Sub

    Public Sub PrintResults()
        For Each r in _linqResults
            Console.Writeline(r.FirstName, r.LastName, r.OrderID)
        Next t
    End Sub

End Class

我一直在寻找 SO 和其他地方,试图找到一个简单的解决方案,但运气不佳。是否有任何方法可以访问包含 Linq 查询的方法范围之外的匿名类型的字段?比如:

Console.Writeline(r("FirstName").ToString, r("LastName").ToString)

可以接受,但并不理想。

我真的、真的不想开始创建额外的类/结构/DTO 来处理应该是动态查询的内容。

【问题讨论】:

    标签: linq-to-objects anonymous-types vb.net-2010


    【解决方案1】:

    不可能以您想要的方式推断类型。不过,您有几个选择:

    1. 创建一个额外的类(你不想要的)

    2. 更改类的样式,使 CreateResults 和 PrintResults 使用与您所做的相同的方法。但是你有充分的理由不这样做。

    3. 使用动态类型(我猜在 VB 中有一个,但我不确定。我是 C# 人),然后您可以像在示例中那样简单地访问所需的属性。这显然不如静态类型快。
    4. 有一个技巧可以做到这一点(至少在 C# 中)。但这并不漂亮。见How to return Anonymous Type while using Linq
    5. 您可以使用元组类,而不是使用自定义类。 System.Tuple 并将数据存储在那里。我认为他们来自 .Net 4。

    最后我真的认为自定义类是要走的路,除非你有充分的理由不这样做。我也想要一种方法来做你想做的事情,但是自定义类可以用更新的语法用几行来描述。

    编辑:添加了几点并稍作改动

    根据要求在 C# 中使用动态示例

    class Foo
    {
        private dynamic _linqResults;
    
        public void CreateResults()
        {
            var someData = Enumerable.Range(1, 10);
    
            _linqResults = from i in someData
                           select new
                           {
                               Number = i
                           };
        }
    
        public void PrintResults()
        {
            foreach (var i in _linqResults)
                Console.WriteLine(i.Number);
        }
    }
    

    如您所见,它几乎与您想要的语法相同。它只是使用慢一点的动态 - 但听起来您已经使用或将在数据网格和 csv 中使用某种动态/反射。这取决于您使用的 DataGrid 和 CSV(您自己的?)。

    正如另一个答案中提到的,编译器无法推断类型,IntelliSense 不会成为您在 PrintResults 中的指南。

    小更新 VB 有一个类似的语法,你可以在这里找到一个很好的遍历: http://blogs.msdn.com/b/vbteam/archive/2008/12/17/walkthrough-dynamic-programming-in-visual-basic-10-0-and-c-4-0-lisa-feigenbaum.aspx

    【讨论】:

    • 感谢 lasseespeholt。由于我的查询结果也将发送到数据网格、csv 文件和报告,我猜附加类是最不糟糕的选择。
    • 好的,谢谢 :) 但是许多 CSV 生成器和数据网格实际上使用反射来写出属性,因此在这种情况下动态方法不一定都是坏事。但这取决于您的数据网格和 CSV 生成器。
    • 您能指出使用动态方法的任何示例吗? C# 示例很好。谢谢。
    • 只是动态示例的替代方案:如果您想要静态类型,那么您可以创建一个私有内部类,而不是使用动态来保存查询结果。更多的工作,但它保持包含新类型并且对任何其他代码不可见。只是另一种可能的实现方式。
    【解决方案2】:

    这是交易。

    您正在创建一个匿名类型。编译器只“知道”匿名类型在其创建的范围内。

    在第二个示例中,您尝试将该匿名类型存储在其创建范围之外。您可以这样做,但由于类型是匿名的,因此您无法访问编译器生成的属性,除非通过反射。

    长话短说,如果您希望将 linq 查询的结果存储在它创建的范围之外,您必须创建一个类型来保存这些结果。

    【讨论】:

      猜你喜欢
      • 2012-07-19
      • 1970-01-01
      • 2011-11-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-07
      • 1970-01-01
      相关资源
      最近更新 更多