C#Custom Collection / Enumerator

时间:2012-06-30 15:26:37

标签: c# generics collections

鉴于以下课程:

public class GenClass<T>
{
     private List<T> ItemsList {get;set;}
     public Predicate<T> SomeCondition {get;set;}
     public bool UsePredicate {get;set;}

     public List<T> Items
     {
         get { //CODE Goes here; }
     }
}

我需要一种方法让列表使用SomeConditionPredicate并仅返回与条件匹配的项目,但仅当bool UsePredicate为真时才返回。我知道我可以只使用LINQ,问题是每次我用LINQ查询时我得到一个IEnumerable的不同实例,这需要是一个属性,因此我需要能够访问List的同一个实例来自课外,因为我将添加和删除它的项目,我不能用。的结果,例如。 我在考虑一个自定义IList<T>,但我不确定该怎么做。

3 个答案:

答案 0 :(得分:2)

这里有一个概念性问题。如果它是同一个实例,它应该如何按条件过滤? LINQ在每次调用时返回新枚举的原因是它运行查询“实时”,并且多个查询必须是独立的。

那就是说,你可能不应该依赖每次返回相同引用的属性。如果您依赖实例是相同的,当/如果有人更改谓词时,您期望发生什么?

如何添加或删除应该在已过滤列表上工作/操作的项目?如果你添加一个可以过滤的项目,会发生什么?

答案 1 :(得分:0)

你的问题有点不清楚,但让我们从这开始:

public class GenClass<T>
{
     private List<T> ItemsList {get;set;}
     public Predicate<T> SomeCondition {get;set;}
     public bool UsePredicate {get;set;}

     public List<T> Items
     {
         get { return UsePredicate 
                   ? ItemsList.Where(SomeCondition).ToList() 
                   : ItemsList; }
     }
}

那对你的用例怎么样?

答案 2 :(得分:0)

IEnumerable只能用于读取集合,但不能用于更改集合。如果要对其进行更改,请返回已过滤索引的枚举。

public IEnumerable<int> FilteredIndexes
{
    get
    {
        if (UsePredicate) {
            return ItemsList
                .Select((item, i) => i)
                .Where(i => SomeCondition(ItemsList[i]));
        }
        return ItemsList.Select((item, i) => i);
    }
}

假设您已声明此索引器

public T this[int index]
{
    get { return ItemsList[index]; }
    set { ItemsList[index] = value; }
}

您现在可以使用这样的集合

GenClass<string> stringCollection = new GenClass<string>();
//TODO: Add items
stringCollection.SomeCondition = s => s.StartsWith("A");
stringCollection.UsePredicate = true;
foreach (int index in stringCollection.FilteredIndexes) {
    stringCollection[index] = stringCollection[index] + " starts with 'A'";
}

更新

如果您不想公开索引,可以创建一个用作项目访问者的类来表示您的集合项

public class Item<T>
{
    private List<T> _items;
    private int _index;

    public Item(List<T> items, int index)
    {
        _items = items;
        _index = index;
    }

    public T Value
    {
        get { return _items[_index]; }
        set { _items[_index] = value; }
    }
}

在您的收藏中,您将声明此属性

public IEnumerable<Item<T>> FilteredItems
{
    get
    {
        if (UsePredicate) {
            return ItemsList
                .Select((item, i) => new Item<T>(ItemsList, i))
                .Where(item => SomeCondition(item.Value));
        }
        return ItemsList.Select((item, i) => new Item<T>(ItemsList, i));
    }
}

现在你可以像这样使用

foreach (Item<string> item in stringCollection.FilteredItems) {
    item.Value = item.Value + " starts with 'A'";
}

一般说明:您可以安全地将私有属性转换为字段。属性通常用作公开公开字段值的中间体。