我的个人编码风格属于Enumerable.OfType<T>()
。我在任何地方使用它都有点意义。特别是IEnumerable<T>
允许强大的linqToObject功能。我讨厌ObjectCollections的“类型不安全”循环,例如下面的示例。现在我有一些关于循环这些“UnGenericCollections”的问题。
ConfigurationSectionCollection
HttpModuleCollection
SPBaseCollection
SPFieldCollection
ArrayList
问题1:如果我将此ArrayList
转换为Enumerable<T>
与简单的foreach / if-checks相比,附加循环有多大?
var ark = new ArrayList();
ark.Add(new Human());
ark.Add(new Human());
ark.Add(new Animal());
而不是:
foreach (object passenger in ark)
{
if (passanger is Human) { }
if (passanger is Animal) { }
}
我用:
foreach (var human in ark.OfType<Human>())
{
}
foreach (var animal in ark.OfType<Animal>())
{
}
问题2:在foreach循环中使用不同类型的变量,将使用哪种投射/转换方式?这是一种语言功能还是开箱即用?
foreach (Human human in ark) { }
感谢您忍受我可怕的英语。最好的问候,本杰明
答案 0 :(得分:2)
答案1:
在您的示例中 - 您实际上可能会迭代 FULL 两次。
// i use
foreach (var human in ark.OfType<Human>())
{
}
foreach (var animal in ark.OfType<Animal>())
{
}
答案2:
如果ark中存在任何非人类,则会抛出InvalidCastException异常。
我个人更喜欢ark.OfTypes<T>()
,如果我知道我只想处理Human
和Animals
,但会忽略Elves
。这样代码更清晰,你在foreach循环中处理强类型对象。
但是,如果我不想忽略Elves
,我会通过完整的ArrayList重复迭代并使用强制转换。
答案 1 :(得分:2)
你会发现没有区别,因为ArrayList实现了IEnumerable。实际上,任何实现此接口的东西都可以在foreach语句中使用。
转换对象而不是设置var将构建(因为它是显式转换)但是如果在枚举中有动物,则最终必须处理转换异常。
foreach (Animal animal in ark) { } // this will blow up an exception if the object is Human
答案 2 :(得分:2)
为了防止集合被迭代两次并保留某种甜蜜的语法,我会提供一个扩展方法,允许为指定类型链接foreach。 我觉得这很有趣:
static void Main(string[] args)
{
var ugly = new ArrayList();
ugly.Add("strings are evil");
ugly.Add("yeah");
ugly.Add(1);
ugly.Add(3);
ugly.Add(1234);
ugly.WithType<int>(x => Console.WriteLine("im a lousy int! " + x))
.AndType<string>(x => Console.WriteLine("and im dangerous string: " + x))
.Execute();
Console.ReadKey();
}
static TypedCollectionView WithType<T>(this IEnumerable x, Action<T> action)
{
return new TypedCollectionView(x).AndType(action);
}
class TypedCollectionView
{
private readonly IEnumerable collection;
private readonly Dictionary<Type, Action<object>> actions = new Dictionary<Type, Action<object>>();
public TypedCollectionView(IEnumerable collection)
{
this.collection = collection;
}
public TypedCollectionView AndType<T>(Action<T> action)
{
actions.Add(typeof(T), o => action((T)o));
return this;
}
public void Execute()
{
foreach (var item in collection)
{
var itemType = item.GetType();
foreach (var action in actions.Where(kv.Key.IsAssignableFrom(itemType)).Select(kv.Value))
{
action(item);
}
}
}
}
所以..现在如何减少这个? :d
答案 3 :(得分:0)
Enumerable.OfType
将检查所有元素并执行is T
检查。因此,每个OfType
调用都将遍历集合中的所有元素。那一定要慢一些。但是如果它更慢到达你的程序就不应该这样做了。
我认为如果在一个集合中放置没有相同父类的类的对象是有意义的。也许你可以找到一些抽象,然后在foreach中将所有对象转换为基类并使用多态调用。