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 { //CODE Goes here; }
     }
}

我需要一种方法让列表使用SomeConditionPredicate并仅返回与条件不匹配的项目,但前提是 boolUsePredicate为真。我知道我可以为此使用 LINQ,问题是每次我使用 LINQ 查询时都会得到一个不同的 IEnumerable 实例,这需要是一个属性,因此我需要能够访问列表的同一个实例从课堂之外,因为我将添加和删除项目,而我不能用 .Where 的结果来做到这一点,例如。我在想一个 custom IList<T>,但我不确定该怎么做。

4

3 回答 3

2

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

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

以及如何添加或删除应该在过滤列表上工作/起作用的项目?如果您添加一个将被过滤掉的项目,会发生什么?

于 2012-06-30T15:33:44.623 回答
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; }
     }
}

那对您的用例不起作用怎么办?

于 2012-06-30T15:38:00.037 回答
0

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

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'";
}

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

于 2012-06-30T16:04:02.203 回答