【问题标题】:Linq with custom base collection带有自定义基础集合的 Linq
【发布时间】:2008-12-16 12:37:55
【问题描述】:

在使用自定义集合对象时,我经常发现 linq 存在问题。 他们经常被辩护为

基础集合

abstract class BaseCollection<T> : List<T> { ... }

集合被定义为

class PruductCollection : BaseCollection<Product> { ... }

有没有更好的方法将 linq expession 的结果添加到此集合中? addrange 还是 concat?

var products = from p in HugeProductCollection
               where p.Vendor = currentVendor
               select p;
PruductCollection objVendorProducts = new PruductCollection();
objVendorProducts.AddRange(products);

如果从 linq 查询返回的对象是我的自定义集合类型,那就太好了。因为您似乎需要枚举集合两次才能执行此操作。

编辑: 阅读答案后,我认为最好的解决方案是实现 ToProduct() 扩展。 想知道 c#4.0 中的协变/逆变是否有助于解决这类问题。

【问题讨论】:

  • “您似乎需要枚举集合两次才能执行此操作。” -- 由于大多数 linq 查询都是惰性求值的,因此集合只会在 AddRange 调用期间被枚举一次。
  • 这解决了我的问题,但我不确定我缺少什么,因为我认为不需要这个临时 BaseCollection&lt;T&gt;。它的目的是什么?

标签: c# linq


【解决方案1】:

问题在于 LINQ 通过IEnumerable&lt;T&gt; 上的扩展方法知道如何构建数组、列表和字典,但它不知道如何构建您的自定义集合。你可以让你的自定义集合有一个带有IEnumerable&lt;T&gt; 的构造函数,或者你可以写给你。前者允许您直接在构造函数中使用 LINQ 结果,后者允许您使用扩展装饰 LINQ 语句并取回您想要的集合。无论哪种方式,您都需要在构造函数或扩展中进行从通用集合到专用集合的某种转换。或者你可以两者都做...

public static class MyExtensions
{
     public static ProductCollection
                      ToProducts( this IEnumerable<Product> collection )
     {
          return new ProductCollection( collection );
     }
}


public class ProductCollection : BaseCollection<Product>
{
     ...

     public ProductCollection( IEnumerable<Product> collection )
              : base( collection )
     {
     }

     ...
 }


var products = (from p in HugeProductCollection
                where p.Vendor = currentVendor
                select p).ToProducts();

【讨论】:

    【解决方案2】:

    我可以建议你一种方法,你不必枚举集合 2 次:

    abstract class BaseCollection<T> : List<T>
    {
        public BaseCollection(IEnumerable<T> collection)
            : base(collection)
        {
        }
    }
    
    class PruductCollection : BaseCollection<Product>
    {
        public PruductCollection(IEnumerable<Product> collection)
            : base(collection)
        {
        }
    }
    
    var products = from p in HugeProductCollection
                   where p.Vendor = currentVendor
                   select p;
    PruductCollection objVendorProducts = new PruductCollection(products);
    

    【讨论】:

      【解决方案3】:

      这可以与 BindingList 一起使用吗?因为 BindingList 没有一个可以接受 IEnumerable 但确实实现它的构造函数。

      BindingList:集合、IBindingList、IList、ICollection、IEnumerable、ICancelAddNew、IRaiseItemChangedEvents

      【讨论】:

      • BindingList 并不适用。 OP 已经能够填充他的自定义集合,因此添加 BindingList 作为额外的中间步骤将无济于事。
      猜你喜欢
      • 1970-01-01
      • 2012-02-04
      • 2014-12-10
      • 1970-01-01
      • 2018-05-16
      • 1970-01-01
      • 2015-09-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多