[英]C# foreach on a collection of an interface
I'm wondering if there is any functionality built in to C#/LINQ to simplify the following: 我想知道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);
...
}
to something along the lines of: 类似于:
collection.ForEachType(Type1 item => DoType1(item), Type2 item => DoType2(item));
I realize that the following is close: 我意识到以下内容很接近:
collection.OfType<Type1>.ToList().Foreach(item => DoType1(item));
collection.OfType<Type2>.ToList().Foreach(item => DoType2(item));
But it does not work when the code is dependent on the order of the collection. 但是,当代码依赖于集合的顺序时,它将不起作用。
The first thing I'd look at is polymorphism; 我要看的第一件事是多态性。 can I instead use a virtual method, and
item.DoSomething()
? 我可以改为使用虚拟方法和
item.DoSomething()
吗?
The next thing I'd look at would be an enum discriminator, ie 接下来要看的是枚举标识符,即
switch(item.ItemType) {
case ItemType.Foo: ...
case ItemType.Bar: ...
}
(and add the discriminator to the common interface/base-class) (并将鉴别符添加到通用接口/基类)
If the types could be anything , then 4.0 has a trick; 如果类型可以是任意值 ,则4.0有一个技巧。 if you call te method the same thing for every overload, you can get
dynamic
to worry about picking it: 如果你调用TE方法每超载同样的事情,你可以得到
dynamic
担心采摘它:
dynamic x = item;
DoSomething(x);
There's nothing built into LINQ, no. LINQ没有内置任何功能,没有。 I would caution you against using
GetType()
like this though - usually it's more appropriate to use is
or as
followed by a null check: 我要提醒你不要使用
GetType()
这样的,虽然-通常它更适合使用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
}
That way derived classes will be treated in a way which is usually the appropriate one. 这样,派生类将以通常合适的方式进行处理。
This sort of type testing is generally frowned upon, mind you - it's generally better to put the behaviour into the type itself as a virtual method, and call it polymorphically. 请注意,这种类型测试通常是令人讨厌的-通常最好将行为作为虚拟方法放入类型本身,然后进行多态调用。
What about something like: 怎么样呢?
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));
This code is untested (typed directly into the browser). 此代码未经测试(直接输入浏览器)。
Your mileage may vary. 你的旅费可能会改变。
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);
}
Here's a version of the matching query which considers derived types (Note, an item may be matched to more than 1 type, and therefore handled multiple times). 这是匹配查询的一个版本,其中考虑了派生类型(请注意,一个项目可能与一种以上类型匹配,因此需要多次处理)。
var typeToActionQuery =
from item in source
from kvp in typeMap
where kvp.Key.IsInstanceOfType(item)
select new
{
input = item;
method = kvp.Value
};
Not by default. 默认不是。 Try Reactive Extensions or Elevate
尝试响应式扩展或提升
The Reactive Extensions and Elevate both contain a ForEach implementation. Reactive Extensions和Elevate都包含一个ForEach实现。 Both have quite a few methods that extend the functionality of linq.
两者都有很多扩展linq功能的方法。
You won't find a ForEachType, but ForEach (Rx or Elevate) and OfType<> (Linq) will give you what you want. 您不会找到ForEachType,但是ForEach(Rx或Elevate)和OfType <>(Linq)将为您提供所需的内容。
在我看来,如果仅将“ item.GetType()== typeof(Type1)”替换为“ item is Type1”,那么您的foreach循环就足够简单了。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.