2

私は持っています:

public Dictionary<string,BaseModel> data  { get; set; }

そして、Linqの遅延実行のみを使用して、現在作業しているこのコードと同等のものを実現したいと考えています。

foreach (KeyValuePair<string, BaseModel> item in data)
{
   T model = (T)item.Value; //each item needs to be cast to T, T inherits from BaseModel
   model.Init(this, personId); //Init is a function I wrote I want to call on each item
   l.Add(model); //currently I am adding each item to a list, but IEnumerable<T> can work
}

次のようなコードを書き始めました。

IEnumerable<T> l = Cache[type].Data.Cast<T>()
                                   .Select(item => item);

しかし、すべてのアイテムで Init 関数を呼び出す方法がわかりません (各モデルには 1 つあり、すべて BaseModel から継承されます)。私は述語デリゲートなどについて読んでいますが、(疑似コード)のようなことをする方法の例を見つけることができません:

IEnumerable<T> l = Cache[type].Data.Cast<T>()
                                   .Select(item => item)
                                   .RunMeOnEachItemLater(InitWrapperDelegate);

これが何のためにあるのか疑問に思っている方のために説明すると、私は MVC プロジェクトを持っており、モデル データ キャッシュを実装しています。

4

4 に答える 4

4

しないでください。LINQを機能的なスタイルで使用することを強くお勧めします-述語に副作用があってはなりません。これは、実行が延期されているためです。つまり、LINQメソッドに渡すラムダは、必要な場合にのみ実行されます。

の要素に何らかの副作用が発生することを確認したい場合は、次IEnumerableを使用してforeachください。

foreach (var model in Cache[type].Data.Select(i=>i.Value).Cast<T>()) {
    model.Init(...);
}

それでも、初期化されていることがわかっているオブジェクトが必要な場合は、LINQ式の結果をフィールドまたは変数にキャッシュすることを検討します。

var models = Cache[type].Data.Select(i=>i.Value).Cast<T>().ToArray();
foreach (var model in models) {
    ...
}

これは、IEnumerableが列挙されるたびに同じアイテムが返されるとは限らないためです。基になるタイプがコレクションである場合は明らかにそうなりますが、それがわかっている場合は、これを表現するICollection代わりに使用する必要があります。IEnumerable

Initキャッシュから物をフェッチするたびに再実行できるようにべき等にすることができない場合は、モデルをキャッシュに追加するときにモデルを初期化するか、ライフサイクルをクリーンアップする必要があります。

于 2012-10-31T22:15:59.673 に答える
1

List(T).ForEach次のような方法を使用できます。

var l = Cache[type].Data.Cast<T>().ToList().ForEach(InitWrapperDelegate);
于 2012-10-31T22:14:33.533 に答える
1

Why not to convert your pseudo-code to real code?

public static class MyExtensions
{
  public static IEnumerable<T> RunMeOnEachItemLater(this IEnumerable<T> sequence,
                                                    Action<T> action)
  {
      foreach(T item in sequence)
      {
         action(item);
         yield return item;
      }
  }
}

Now you can execute custom function for each item later using LINQ deferred execution:

IEnumerable<BaseModel> l = Cache[type].Data.Cast<BaseModel>()
                                           .RunMeOnEachItemLater(m => m.Init());
于 2012-10-31T22:49:12.780 に答える
-1

同等の機能は次のようになります。

var list = data.Values.Cast<T>()
    .Select(x=>
    {
        x.Init(this, personId); 
        return x;
    })
    .ToList();

.ToList()を削除してを返すことができ、リストが列挙されているときIEnumerable<T>Init呼び出しが後で実行されることに注意してください。

于 2012-10-31T22:14:12.530 に答える