ToList<>()所带来的性能影响

通过对大量数据使用PLINQ查询并结合ToList()和Count()方法导致性能严重下降的问题进行分析,发现去掉这两个方法并采用替代方案能显著提高程序运行效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 前几天优化师弟写的代码,有一个地方给我留下很深刻的印象,就是我发现他总是将PLINQ的结果ToList<>(),然后再返回给主程序,对于这一点我十分不解,于是去问他是什么原因,得到的答案很幽默:因为习惯。
    有时候对于方法的不甚了解加上“习惯”,往往是程序性能和稳定性终结者,就拿这个Case来说吧,原始代码如下:
 

var query = from cr in LCRNormal.AsParallel()
                        let listId = from crt in LCRNormal
                                     group crt by crt.KeyValue into m
                                     select m.Max(n => n.DBID)
                        where listId.Contains(cr.DBID) && !cr.IsRegularRecord && cr.Status != 3
                        select new ComputingResultForTemp()
                        {
                            KeyValue = cr.KeyValue,
                            DBID = cr.DBID,
                            Status = cr.Status
                        };

query.ToList<ComputingResultForTemp>();

  

    经过以上PLINQ后,泛型列表中大概还剩下60万至100万条数据,然后我们这位师弟做了两个很“施瓦辛格”的动作:ToList<>()和Count(),测试程序运行在一台4*2G HZ,12GB内存的服务器上,竟然跑了2天多!我觉得正式这两个方法导致了程序性能的降低,为了  确定我的判断,我分别在以上代码、ToList<>()和Count()周围加上了StopWatch计时器,然后将结果以文本的形式输出:
    ● 100万数据PLINQ查询:
           ==========3/26/2011 01:34:31 PM ===========
           **(GetDeletedRecords)Start PLINQ(LINQ FITTER)
           ==========3/26/2011 01:38:38 PM ===========
           **(GetDeletedRecords)Finish PLINQ (LINQ FITTER)
   ●  80万数据ToList <>():
           ==========3/26/2011 03:22:10 PM ===========
           **(GetDeletedRecords)Start Get List
●  80万数据Count():
           ==========3/28/2011 02:12:09 PM ===========
           **(GetDeletedRecords)Start Get Count
           ==========3/28/2011 08:50:55 PM ===========
           ** (GetDeletedRecords)Finish Get Count
    日志格式是这样:任务开始时输出当前时间和“Start”,任务结束时输出“Finish”,当从日志中可以看出,PLINQ的效率还是很高的,只运行了几分钟;ToList<>()方法在运行了1天多后人为终止,所以只有Start没有Finish;Count()方法也运行了6小时多。
    所以最终优化方案很简单,去掉了ToList和Count,改用其他方法代替,程序从几天的运行时间一下缩短到几个小时。


本文转自Aicken(李鸣)博客园博客,原文链接:http://www.cnblogs.com/isline/archive/2011/05/10/2041822.html,如需转载请自行联系原作者

<think>好的,用户的问题是如何将C#中的匿名类型列表`List<new {string name, doublevalue }>`转换为嵌套的泛型列表`List<List<>>`结构。首先,我需要理解用户的具体需求。匿名类型在C#中是不可见的,无法直接作为泛型参数使用,所以用户可能遇到了类型转换的问题。接下来,我需要考虑匿名类型的特性。匿名类型的属性是只读的,且无法在方法之间传递,除非使用`object`类型,但这会导致类型信息丢失。因此,直接将匿名类型转换为`List<List<>>`可能有困难。用户提到的`List<List<>>`结构,这里可能需要明确嵌套列表的具体类型。例如,是否每个内部列表包含字符串和数值,还是其他结构。假设用户希望将每个匿名对象转换为包含`name`和`value`的列表,那么外部列表中的每个元素可能是一个包含两个元素的列表,比如`List<List<object>>`或者使用具体类型如`string`和`double`。接下来,我需要考虑如何提取匿名类型的属性。由于匿名类型的属性在编译时确定,可以通过反射来获取属性值,但这样做效率不高。另一种方法是使用动态类型(`dynamic`),但这也可能带来运行时错误。然后,参考用户提供的引用内容,特别是引用[1]和[2]中关于`Dictionary`和`HashTable`的区别,可能涉及到类型安全和装箱拆箱的问题。在转换匿名类型时,可能需要避免装箱操作,但匿名类型本身就是引用类型,所以可能需要处理类型转换。可能的解决方案包括: 1.使用LINQ的`Select`方法将每个匿名对象转换为`List<object>`,然后收集到外层列表中。例如:```csharpvar result= anonymousList.Select(a =>new List<object> {a.name, a.value }).ToList();```这会生成一个`List<List<object>>`。2.如果用户希望保留类型信息,可能需要使用元组(Tuple)或自定义类来代替匿名类型,这样泛型参数就可以明确指定,例如`List<Tuple<string,double>>`,然后转换为`List<List<object>>`。3.如果必须使用匿名类型,可能需要使用反射来动态获取属性值,但这样代码会复杂且效率较低。 还需要考虑用户的实际应用场景。例如,是否需要在不同方法之间传递这个嵌套列表,或者是否需要序列化。如果涉及跨方法传递,建议使用命名类型代替匿名类型,以提高代码的可维护性和类型安全性。另外,用户可能没有意识到匿名类型的局限性,比如无法在不同作用域中使用相同的匿名类型,即使属性结构相同。因此,建议用户使用明确的数据结构,如元组或自定义类,来替代匿名类型,这样可以更方便地进行类型转换和操作。 总结可能的步骤: -将匿名列表中的每个对象转换为包含属性的列表元素。 -使用LINQ进行转换,生成嵌套列表。 -考虑类型安全和性能问题,推荐使用具体类型而非匿名类型。 最后,需要验证这些方法是否有效,例如编写示例代码测试转换过程,并确保没有运行时错误。同时,提醒用户注意匿名类型的限制,以及可能的替代方案。</think>### 如何将匿名类型列表转换为嵌套泛型列表 在C#中,匿名类型无法直接作为泛型参数使用,但可以通过以下两种方法实现类似`List<List<>>`的结构: --- #### 方法一:通过动态类型转换(类型安全但需明确属性顺序) 若匿名类型属性已知(例如`name`和`value`),可通过`Select`逐层提取属性值,构造嵌套列表: ```csharp var anonymousList = new[] { new { name = "A", value = 1.0 }, new { name = "B", value = 2.0 } }.ToList(); // 转换为 List<List<object>> List<List<object>> nestedList = anonymousList .Select(item => new List<object> { item.name, item.value }) .ToList(); ``` - **优点**:直接利用LINQ实现,代码简洁。 - **缺点**:需手动维护属性顺序,类型需强制转换为`object`[^1]。 --- #### 方法二:使用元组(Tuple)替代匿名类型 匿名类型无法跨方法传递,但元组可以: ```csharp var tupleList = new List<Tuple<string, double>> { Tuple.Create("A", 1.0), Tuple.Create("B", 2.0) }; // 转换为 List<List<object>> List<List<object>> nestedList = tupleList .Select(t => new List<object> { t.Item1, t.Item2 }) .ToList(); ``` - **优点**:类型安全,无需反射或动态类型。 - **缺点**:需提前将匿名类型替换为元组[^2]。 --- #### 方法三:反射提取属性值(适用于未知结构) 若匿名类型结构未知,可通过反射动态获取属性: ```csharp List<List<object>> nestedList = new List<List<object>>(); foreach (var item in anonymousList) { var properties = item.GetType().GetProperties(); List<object> innerList = properties .Select(p => p.GetValue(item)) .ToList(); nestedList.Add(innerList); } ``` - **优点**:通用性强,适应不同匿名类型。 - **缺点**:性能较低,且需处理异常[^1]。 --- ### 关键问题与建议 1. **类型约束**:匿名类型的属性不可修改,且无法跨方法传递,建议优先使用命名类型(如`class`或`struct`)[^2]。 2. **性能优化**:反射会影响性能,高频场景推荐方法二。 3. **嵌套结构设计**:若需强类型,可定义`List<List<T>>`并指定`T`为具体类型。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值