代码之家  ›  专栏  ›  技术社区  ›  Russ

如何在Linq中将匿名类型转换为强类型?

  •  17
  • Russ  · 技术社区  · 16 年前

    我有一个列表视图项数组( ListViewItem[] )我在哪里存储 SalesOrderMaster 每个ListViewItem.tag中的对象,供以后参考。

    我现在有一些代码,每个代码都经过 ListViewItem 安全地将.tag属性强制转换为SalesOrderMaster对象,然后将该对象添加到SalesOrders集合中,仅在检查以确保该集合中不存在订单之后。

    过程到 比较 销售订单很贵,为了清晰和性能,我想将其转换为LINQ表达式。(我也有 Parallel Extensions to .NET Framework 3.5 已安装,因此我可以使用它进一步提高LINQ性能)

    所以不用再费劲了:这就是我拥有的,然后就是我想要的。(我想要的不会编译,所以我知道我做错了什么,但我希望它能说明这一点)

    我有什么:(慢)

    foreach (ListViewItem item in e.Argument as ListViewItem[])
                {
                    SalesOrderMaster order = item.Tag as SalesOrderMaster;
                    if ( order == null )
                    {
                        return;
                    }
                    if (!All_SalesOrders.Contains(order))
                    {
                        All_SalesOrders.Add(order);
                    }
                }
    

    我想要的:(理论)

        List<SalesOrderMaster> orders = 
    (from item in (e.Argument as ListViewItem[]).AsParallel() 
    select new { ((SalesOrderMaster)item.Tag) }).Distinct();
    

    编辑:我知道演员阵容很便宜,我说的是“比较”,在本例中翻译为.contains(order)操作

    编辑:每个人的回答都很棒!我希望我能标记多个答案,但最后我必须选择一个。

    编辑:这就是我的结局:

    List<SalesOrderMaster> orders = 
    (from item in (e.Argument as ListViewItem[]) select (SalesOrderMaster) item.Tag).GroupBy(item => item.Number).Select(x => x.First()).ToList();
    
    3 回复  |  直到 12 年前
        1
  •  17
  •   Lucas    16 年前

    我发现没有人能满足您将匿名类型显式转换为命名类型的需要,所以这里……用“ select new { } “您正在创建匿名类型,但不需要。您可以这样编写查询:

    List<SalesOrderMaster> orders = 
        (from item in (e.Argument as ListViewItem[]).AsParallel() 
        select (SalesOrderMaster)item.Tag)
        .Distinct()
        .ToList();
    

    请注意,查询选择 (SalesOrderMaster)item.Tag 没有 new { } ,因此它不会创建匿名类型。同时注意我添加了 ToList() 因为你想要一个 List<SalesOrderMaster> .

    这就解决了匿名类型的问题。但是,我同意Mark和Guffa的观点,在这里使用并行查询不是最佳选择。使用 HashSet<SalesOrderMaster> 正如Guffa建议的那样,你可以这样做:

    IEnumerable<SalesOrderMaster> query = 
        from item in (ListViewItem[])e.Argument
        select (SalesOrderMaster)item.Tag;
    
    HashSet<SalesOrderMaster> orders = new HashSet<SalesOrderMaster>(query);
    

    (我避免使用 var 因此,示例中返回的类型是清晰的。)

        2
  •  3
  •   Guffa    16 年前

    代码中代价高昂的部分是调用 Contains 方法。因为它是一个O(N)操作,所以添加到列表中的对象越多,它就越慢。

    只使用一个 HashSet<SalesOrderMaster> 对象而不是 List<SalesOrderMaster> . 这个 包含 方法 HashSet 是O(1)操作,因此循环将是O(n)操作,而不是O(n*n)操作。

        3
  •  3
  •   configurator    16 年前

    就像马克·格雷威尔说的,你不应该进入 Tag 属性来自不同的线程,而强制转换非常便宜,因此您有:

    var items = (e.Argument as ListViewItem[]).Select(x=>x.Tag)
             .OfType<SalesOrderMaster>().ToList();
    

    但之后,您需要找到不同的项目-在这里您可以尝试使用 AsParallel :

    var orders = items.AsParallel().Distinct();