[英]Efficient run-time type checking
我有如下类的层次结构(实际上我有超过 3 个派生类型):
class A {};
class B : A {};
class C : B {};
class D : A {};
这些类的实例存储在List<A>
collections 中。 有时 collections 相当大(数千甚至数万个对象)。
在我的代码中,我经常需要根据对象的确切类型执行一些操作。 像这样的东西:
List<A> collection = ...
foreach (A obj in collection)
{
if (obj is C)
something(obj as C);
else if (obj is B)
somethingElse(obj as B);
....
}
如您所见,代码对 object 的类型和强制转换执行了许多检查。 对于具有许多元素的 collections,代码的性能并不是那么好。
在我的情况下,您会建议什么来加快运行时类型检查?
在我看来,您应该将“某物”移动到A
上的虚拟方法中,然后B
、 C
和D
中的每一个都可以根据需要覆盖它(这可能只是意味着调用外部方法 - 他们不需要这样做工作本身) - 或者不根据需要覆盖。
那么这就变成了:
foreach (A obj in collection)
{
obj.DoSomething();
}
IE
class A {
public virtual void DoSomething() {...}
}
class B : A {
public override void DoSomething() {...}
}
ETC
使 function “某事”中实现的功能成为 Class A 的行为/方法,然后在适用的子类中重新定义它(确保该方法被定义为虚拟)。
在这种情况下,您可以立即致电:
List<A> collection = ...
foreach (A obj in collection)
{
obj.something()
}
仅用as
并检查 null 代替:
C c = obj as C;
if (c != null)
something(c);
它只会执行一次投射。 as
和is
实际上都执行强制转换,因此实际上没有必要一起使用它们。
话虽如此,铸造相对便宜。 强制转换的任何性能损失都应该与something(c)
或something(b)
的实现相形见绌,所以不要想太多,除非你尝试转换的类型数量非常大。
如果您控制A
, B
, C
类,请查看您是否可以返工您的 model ,因此您根本不需要进行铸造 - 使用其他人建议的虚拟方法。
使用as
或is
没有明显的性能差异。 然而,我在框架中看到的是它们为每种类型提供了一个具有唯一值的枚举。 这样您就可以打开 object 的类型。
表达式树就是这样做的,它们有一个名为NodeType
的属性,它返回一个包含该类型的值。 这样您就不需要做不止一种类型的测试。
再一次,Marc 只是提醒我,有时可以通过正确使用多态性来解决这些类型的情况,并且您遇到此问题可能表明您编写类的方式存在潜在问题。
在我看来,您应该只使用虚拟方法。 它将产生更易读的高效代码。
通常干净的解决方案是虚拟方法。 但有时这是不可能的。 在这种情况下,您可以使用Dictionary<Type,Action>
。
Dictionary<Type,Action> actions=new Dict...;
Action action;
if(!actions.TryGetValue(obj.GetType(), out action))
{
action=GetActionForType(obj.GetType());
actions.Add(obj.GetType(), action);
}
action();
请注意,这仅适用于确切类型,不适用于派生类型。 因此,您可能需要在GetActionForType
中添加一些基于Type.IsAssignableFrom
的逻辑。
显然这个实现不是线程安全的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.