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()吗?

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

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

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

如果类型可以是任何东西,那么 4.0 有一个窍门;如果您对每个重载都调用 te 方法,那么您可能会dynamic担心选择它:

dynamic x = item;
DoSomething(x);
于 2011-09-29T18:01:58.150 回答
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
}

这样,派生类将以一种通常是适当的方式处理。

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

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

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

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

默认情况下不是。尝试响应式扩展提升

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

你不会找到 ForEachType,但 ForEach(Rx 或 Elevate)和 OfType<>(Linq)会给你你想要的。

于 2011-09-29T17:58:47.700 回答
0

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

于 2011-09-29T18:01:31.277 回答