C#foreach在一个接口的集合上

时间:2011-09-29 17:54:42

标签: c# linq generics generic-collections

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

但是当代码依赖于集合的顺序时,它不起作用。

6 个答案:

答案 0 :(得分:6)

我要看的第一件事是多态性;我可以使用虚拟方法和item.DoSomething()吗?

接下来我要看的是枚举鉴别器,即

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

(并将鉴别器添加到公共接口/基类)

如果类型可能是任何,那么4.0有一个技巧;如果你为每次重载调用te方法都是一样的话,你可以让dynamic担心选择它:

dynamic x = item;
DoSomething(x);

答案 1 :(得分:5)

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
}

这样,派生类将以通常合适的方式处理。

这种类型测试通常不受欢迎,请注意 - 通常最好将行为作为虚方法放入类型本身,并以多态方式调用它。

答案 2 :(得分: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));

此代码未经测试(直接在浏览器中输入)。

答案 3 :(得分: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);
}

这是匹配查询的一个版本,它考虑派生类型(注意,一个项目可以匹配多于一种类型,因此可以多次处理)。

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

答案 4 :(得分:0)

默认不是。试试Reactive ExtensionsElevate

Reactive Extensions和Elevate都包含ForEach实现。两者都有很多方法可以扩展linq的功能。

您将找不到ForEachType,但ForEach(Rx或Elevate)和OfType&lt;&gt; (Linq)会给你你想要的东西。

答案 5 :(得分:0)

在我看来,如果您只是将“item.GetType()== typeof(Type1)”替换为“item is Type1”,那么您的foreach循环将非常简单。