Skip to main content
 首页 » 编程设计

c#之如何在 C# 中最优雅地从匿名集合创建空集合

2024年01月18日29wayfarer

如果我有一个由 LINQ 创建的匿名类型

var ans = from r in someList where someCondition(r) select new { r.a, r.b }; 

创建一个空的匹配集合以便我可以将元素移动到新集合的最佳方法是什么:

var newans = ? 
foreach (r in ans) { if (complicated(r)) newans.Add(r); } 

有什么方法可以使用 Enumerable.Empty<>() 吗?

请您参考如下方法:

我不会使用 ans.Where(x => false).ToList()这些版本迭代所有你不需要的元素; ans.Take(0).ToList()好一点,因为当您查询内存中的序列(LINQ to Objects)时,这个实际上不会遍历整个列表。

如果您使用 LINQ to SomethingElse,事情就会有点问题,因为它实际上可能会执行类似于 SELECT TOP(0) * FROM ... 的操作。或 SELECT * FROM ... WHERE 1 = 0 .不好。

所以下面的辅助方法会帮助你:

public static class AnonymousTypeExtensions 
{ 
    public static List<T> ToEmptyList<T>(this IEnumerable<T> source) 
    { 
        return new List<T>(); 
    } 
} 
 
var newans = ans.ToEmptyList(); 

话虽如此,如果您唯一的愿望是复制 ans 的某些元素进入一个新列表,你最好用

var newans = (from a in ans where isComplicated(a) select a).ToList(); 

或

var newans = ans.Where(a => isComplicated(a)).ToList(); 

如果您不需要实际的 List<T> , 和一个 IEnumerable<T>就足够了,您可以省略 ToList共。请注意,每次你对这样一个可枚举的对象进行 foreach 时,Where(a => isComplicated(a))被一次又一次地执行。调用ToList确保你只执行一次。


如果你不想要这个只是为了 List<T> ,但更一般地说,事情变得更加复杂。例如,该方法是否应该返回 ans 的静态类型?变量或其运行时类型?此外,除了盲目调用 new C() 之外,许多集合没有“默认”版本。 .但这一般行不通。无法调用 new ReadOnlyCollection<T>() ,因为它不存在(并且集合无论如何都会被密封,因此无法填充)。如果您使用的是 HasSet,难道您不应该为您的空副本使用原始比较器而不是默认比较器吗?

但是,对于最简单的情况,您可以尝试:

public static class CollectionExtensions 
{ 
    public static TCollection AsEmpty<TCollection>(this TCollection source) 
        where TCollection : ICollection, new() 
    { 
        return new TCollection(); 
    } 
} 

请注意,这是一个编译时解决方案,它返回变量 类型的默认集合。如果可能的话。例如ans = from r in somesource select new { ... }将具有静态类型 IEnumerable<...> .这里没有要创建的默认实例。此外,select 返回的运行时类型是 System.Core.dll 私有(private)的,没有默认构造函数,并且无论如何都是只读的类似游标的类型。

所以我对这个的看法是:不要去那里。不要试图过度概括,坚持简单的解决方案,如 ToEmptyList 或更好的解决方案,坚持简单的 LINQ 方法链。