簡體   English   中英

接口集合上的C#foreach

[英]C# foreach on a collection of an interface

我想知道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));

但是,當代碼依賴於集合的順序時,它將不起作用。

我要看的第一件事是多態性。 我可以改為使用虛擬方法和item.DoSomething()嗎?

接下來要看的是枚舉標識符,即

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

(並將鑒別符添加到通用接口/基類)

如果類型可以是任意值 ,則4.0有一個技巧。 如果你調用TE方法每超載同樣的事情,你可以得到dynamic擔心采摘它:

dynamic x = item;
DoSomething(x);

LINQ沒有內置任何功能,沒有。 我要提醒你不要使用GetType()這樣的,雖然-通常它更適合使用isas后跟一個空檢查:

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
}

這樣,派生類將以通常合適的方式進行處理。

請注意,這種類型測試通常是令人討厭的-通常最好將行為作為虛擬方法放入類型本身,然后進行多態調用。

怎么樣呢?

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));

此代碼未經測試(直接輸入瀏覽器)。

你的旅費可能會改變。

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);
}

這是匹配查詢的一個版本,其中考慮了派生類型(請注意,一個項目可能與一種以上類型匹配,因此需要多次處理)。

var typeToActionQuery =
  from item in source
  from kvp in typeMap
  where kvp.Key.IsInstanceOfType(item)
  select new
  {
    input = item;
    method = kvp.Value
  };

默認不是。 嘗試響應式擴展提升

Reactive Extensions和Elevate都包含一個ForEach實現。 兩者都有很多擴展linq功能的方法。

您不會找到ForEachType,但是ForEach(Rx或Elevate)和OfType <>(Linq)將為您提供所需的內容。

在我看來,如果僅將“ item.GetType()== typeof(Type1)”替換為“ item is Type1”,那么您的foreach循環就足夠簡單了。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM