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、条件に一致するアイテムのみを返す方法が必要ですが、ブール値UsePredicateが true の場合のみです。これにはLINQを使用できることはわかっています。問題は、LINQでクエリを実行するたびに、IEnumerableの異なるインスタンスを取得することです。これはプロパティである必要があるため、リストの同じインスタンスにアクセスできる必要がありますクラスの外からアイテムを追加したり削除したりしますが、たとえば.Whereの結果ではそれを行うことができないためです。カスタムを考えていたのIList<T>ですが、どうすればいいのかよくわかりません。

4

3 に答える 3

2

ここに概念的な問題があります。同じインスタンスである場合、条件によってどのようにフィルタリングすることになっていますか? 呼び出しごとに LINQ が新しい列挙を返す理由は、LINQ がクエリを "ライブ" で実行し、複数のクエリが独立している必要があるためです。

とはいえ、毎回同じ参照を返すプロパティに依存する必要はないでしょう。インスタンスが同じであることに依存している場合、誰かが述語を変更した場合に何が起こると思いますか?

また、フィルタリングされたリストで機能/動作するはずのアイテムを追加または削除するにはどうすればよいですか? 除外される項目を追加するとどうなりますか?

于 2012-06-30T15:33:44.623 に答える
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'";
}

一般的な注意: プライベート プロパティを安全にフィールドに変換できます。プロパティは通常、フィールド値を公開するための中間手段として使用されます。

于 2012-06-30T16:04:02.203 に答える
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 に答える