繁体   English   中英

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

[英]How can I create an empty collection from an anonymous collection most elegantly in C#?

如果我有一个由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了。 提醒您,每次在这样的枚举上进行遍历时,都会一次又一次执行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的私有类型,没有默认构造函数,并且还是只读的类似游标的类型。

所以我对此的看法是:不要去那里。 不要过度概括,坚持使用ToEmptyList之类的简单解决方案,甚至更好,坚持使用简单的LINQ方法链。

我没有尝试过,但是

var newans = from r in ans where false select r;

似乎是一种生成正确类型的IEnumerable的方法(但不是可以“添加”到的集合-可以将其列出)。

就是说,如果您使用的是LINQ,似乎不太可能拥有问题中包含的“ foreach-if-.add”代码,

var newans = from r in ans where isComplicated(r) select r;

要么

var newans = ans.Where(isComplicated);

没有?

var newans = ans.Where(false).ToList()将执行此操作。

无法使用Enumerable.Empty因为无法显式传递匿名类型作为泛型参数。

使用var newans = ans.ToList(); 它将每个枚举的对象复制到一个新列表中。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM