【问题标题】:How can I create an empty collection from an anonymous collection most elegantly in C#?如何在 C# 中最优雅地从匿名集合创建一个空集合?
【发布时间】:2011-02-22 03:11:18
【问题描述】:

如果我有一个由 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()?

【问题讨论】:

  • 发帖前你搜索过吗?这是stackoverflow.com/questions/661663/anonymous-type-collections的骗子
  • 建议一个搜索结果?我搜索了谷歌,我搜索了这里,我尝试了多个标签和关键字。不是一个适合搜索的主题。我确实尝试仅搜索集合,但错过了与我相关的问题,因为在内部我想要一些更通用的东西,它不仅仅处理 List 类型,而是任何 var 变量。

标签: c# linq collections


【解决方案1】:

我不会使用这些迭代所有元素的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&lt;T&gt;,而IEnumerable&lt;T&gt; 就足够了,您可以完全省略ToList。请注意,每次您遍历这样一个可枚举的对象时,Where(a =&gt; isComplicated(a)) 都会一次又一次地执行。对ToList 的调用确保您只执行一次。


如果您不希望仅针对List&lt;T&gt; 进行此操作,而是更一般地,事情会变得更加复杂。例如,该方法应该返回ans 变量的静态类型还是它的运行时类型?此外,除了盲目地调用new C() 之外,没有许多集合的“默认”版本。但这通常行不通。无法调用new ReadOnlyCollection&lt;T&gt;(),因为它不存在(而且集合无论如何都会被密封,因此无法填充)。如果您使用的是 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&lt;...&gt;。这里没有要创建的默认实例。此外,select 返回的运行时类型是 System.Core.dll 私有的,没有默认构造函数,并且无论如何都是只读游标类型。

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

【讨论】:

  • 这非常好 - 似乎是语言应该具备的那种东西,但是当 var ans 不是 List 时,它可以被泛化处理吗?
  • 这适用于任何 IEnumerable(包括 LINQ 查询),适用于任何 T。否则我可能无法完全理解您的问题。
  • 它将任何 IEnumerable 转换为一个空的 List,但是为任何 X 创建一个空的 X 怎么样? var v = Default(ans) 怎么样?
  • 我已经详细说明了那部分。简单地说:不要那样做:-)
  • +1,很好的答案。解决了一些超越 OP 问题的编码风格建议。
【解决方案2】:

我没试过,但是

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

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

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

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

var newans = ans.Where(isComplicated);

没有?

【讨论】:

    【解决方案3】:

    var newans = ans.Where(false).ToList() 会做到的。

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        猜你喜欢
        • 2010-11-24
        • 2019-10-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-30
        • 1970-01-01
        • 2021-09-15
        相关资源
        最近更新 更多