繁体   English   中英

高效的运行时类型检查

[英]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上的虚拟方法中,然后BCD中的每一个都可以根据需要覆盖它(这可能只是意味着调用外部方法 - 他们不需要这样做工作本身) - 或者根据需要覆盖。

那么这就变成了:

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

它只会执行一次投射。 asis实际上都执行强制转换,因此实际上没有必要一起使用它们。

话虽如此,铸造相对便宜。 强制转换的任何性能损失都应该与something(c)something(b)的实现相形见绌,所以不要想太多,除非你尝试转换的类型数量非常大。

如果您控制ABC类,请查看您是否可以返工您的 model ,因此您根本不需要进行铸造 - 使用其他人建议的虚拟方法。

使用asis没有明显的性能差异。 然而,我在框架中看到的是它们为每种类型提供了一个具有唯一值的枚举。 这样您就可以打开 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM