如何在C#中最优雅地从匿名集合中创建一个空集合?

Net*_*age 1 c# linq collections

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

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

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

var newans = ?
foreach (r in ans) { if (complicated(r)) newans.Add(r); }
Run Code Online (Sandbox Code Playgroud)

有没有办法使用Enumerable.Empty <>()?

Rub*_*ben 6

我不会使用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();
Run Code Online (Sandbox Code Playgroud)

话虽如此,如果你唯一的愿望是将一些元素复制ans到一个新的列表中,你最好还是有

var newans = (from a in ans where isComplicated(a) select a).ToList();
Run Code Online (Sandbox Code Playgroud)

要么

var newans = ans.Where(a => isComplicated(a)).ToList();
Run Code Online (Sandbox Code Playgroud)

如果你不需要一个实际的List<T>,一个IEnumerable<T>就够了,你可能ToList完全省略了.请注意,每当你对这样一个可以说明的事物进行预告时,你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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

所以我对这一点的看法是:不要去那里.不要试图过度概括,坚持像ToEmptyList这样的简单解决方案,甚至更好,坚持使用简单的LINQ方法链接.