1

以下を簡素化するために C#/LINQ に組み込まれている機能があるかどうか疑問に思っています。

foreach(var item in collection)
{
    if (item.GetType() == typeof(Type1)
         DoType1(item as Type1);
    else if (item.GetType() == typeof(Type2))
         DoType2(item as Type2);
    ...
}

次の行に沿ったものに:

collection.ForEachType(Type1 item => DoType1(item), Type2 item => DoType2(item));

私は次のことが近いことを認識しています:

collection.OfType<Type1>.ToList().Foreach(item => DoType1(item));
collection.OfType<Type2>.ToList().Foreach(item => DoType2(item));

ただし、コードがコレクションの順序に依存している場合は機能しません。

4

6 に答える 6

6

私が最初に注目するのはポリモーフィズムです。代わりに仮想メソッドを使用できitem.DoSomething()ますか?

次に注目するのは、enum 識別子です。つまり、

switch(item.ItemType) {
    case ItemType.Foo: ...
    case ItemType.Bar: ...
}

(そして、識別子を共通インターフェイス/基本クラスに追加します)

型がanyである場合、4.0 にはトリックがあります。すべてのオーバーロードに対して同じメソッドを呼び出すと、それをdynamic選択することについて心配するようになる可能性があります。

dynamic x = item;
DoSomething(x);
于 2011-09-29T18:01:58.150 に答える
5

LINQ には何も組み込まれていません。ただし、このように使用しないように注意してください。GetType()通常は、null チェックを使用するisか、その後に続く方が適切です。as

foreach(var item in collection)
{
    Type1 itemType1 = item as Type1;
    if (itemType1 != null)
    {
         DoType1(itemType1);
         continue;
    }
    Type2 itemType2 = item as Type1;
    if (itemType2 != null)
    {
         DoType2(itemType1);
         continue;
    }
    // etc
}

そうすれば、派生クラスは通常適切な方法で処理されます。

この種の型テストは一般的に嫌われています。一般的には、動作を仮想メソッドとして型自体に入れ、多態的に呼び出す方がよいでしょう。

于 2011-09-29T17:58:33.627 に答える
1

次のようなものはどうですか:

var typeActions = new Dictionary<Type,Action<Object>>();
typeActions.Add(typeof(Type1), obj => DoType1((Type1)obj));
typeActions.Add(typeof(Type2), obj => DoType2((Type2)obj));

collection.Foreach(obj => typeActions[obj.GetType()](obj));

このコードはテストされていません (ブラウザに直接入力)。

于 2011-09-29T18:02:38.330 に答える
1

あなたのマイレージは異なる場合があります。

Dictionary<Type, Action<object>> typeMap = new Dictionary<Type, Action<object>>();
typeMap[typeof(Type1)] = item => DoType1(item as Type1);
typeMap[typeof(Type2)] = item => DoType2(item as Type2);

var typeToActionQuery =
  from item in source
  let type = item.GetType()
  where typeMap.ContainsKey(type)
  select new
  {
    input = item;
    method = typeMap[type]
  };

foreach(var x in typeToActionQuery)
{
  x.method(x.input);
}

派生型を考慮したマッチング クエリのバージョンを次に示します (1 つのアイテムが複数の型に一致する可能性があるため、複数回処理されることに注意してください)。

var typeToActionQuery =
  from item in source
  from kvp in typeMap
  where kvp.Key.IsInstanceOfType(item)
  select new
  {
    input = item;
    method = kvp.Value
  };
于 2011-09-29T18:09:09.433 に答える
0

「item.GetType()== typeof(Type1)」を「itemis Type1」に置き換えるだけで、foreachループは十分に単純になるように思われます。

于 2011-09-29T18:01:31.277 に答える
0

デフォルトではありません。Reactive ExtensionsまたはElevateを試す

Reactive Extensions と Elevate の両方に ForEach 実装が含まれています。どちらにも、linq の機能を拡張するかなりの数のメソッドがあります。

ForEachType は見つかりませんが、ForEach (Rx または Elevate) と OfType<> (Linq) で必要なものが得られます。

于 2011-09-29T17:58:47.700 に答える