简体   繁体   English

高效的运行时类型检查

[英]Efficient run-time type checking

I have hierarchy of classes like follows (in fact I have more than 3 derived types):我有如下类的层次结构(实际上我有超过 3 个派生类型):

class A {};
class B : A  {};
class C : B  {};
class D : A  {};

Instances of these classes are stored in List<A> collections.这些类的实例存储在List<A> collections 中。 Sometimes collections are quite big (thousands or even tens of thousands of objects).有时 collections 相当大(数千甚至数万个对象)。

In my code I frequently need to perform some actions depending on the exact type of the objects.在我的代码中,我经常需要根据对象的确切类型执行一些操作。 Something like this:像这样的东西:

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

As you see, the code performs many checks for type of the object and casts.如您所见,代码对 object 的类型和强制转换执行了许多检查。 For collections with many elements performance of the code is not that great.对于具有许多元素的 collections,代码的性能并不是那么好。

What would you recommend to speed up run time type checks in my case?在我的情况下,您会建议什么来加快运行时类型检查?

It sounds to me like you should move the "something" into a virtual method on A , then each of B , C and D can override it as they need (which may just mean calling an external method - they don't need to do the work themselves) - or not override as they need.在我看来,您应该将“某物”移动到A上的虚拟方法中,然后BCD中的每一个都可以根据需要覆盖它(这可能只是意味着调用外部方法 - 他们不需要这样做工作本身) - 或者根据需要覆盖。

Then this becomes:那么这就变成了:

foreach (A obj in collection)
{
    obj.DoSomething();
}

ie IE

class A {
    public virtual void DoSomething() {...}
}
class B : A   {
    public override void DoSomething() {...}
}

etc ETC

Make the functionality implemented in the function "something" a behaviour/method of Class A and then redefine it in child classes as applicable (make sure the method is defined as virtual).使 function “某事”中实现的功能成为 Class A 的行为/方法,然后在适用的子类中重新定义它(确保该方法被定义为虚拟)。

In this case you can straight away call:在这种情况下,您可以立即致电:

List<A> collection = ...
foreach (A obj in collection)
{
  obj.something()
}

Use only as and check for null instead:仅用as并检查 null 代替:

C c = obj as C;
if (c != null)
    something(c);

It will only perform casting once.它只会执行一次投射。 Both as and is actually perform casting so there is really no need to use them together. asis实际上都执行强制转换,因此实际上没有必要一起使用它们。

That being said, casting is relatively cheap.话虽如此,铸造相对便宜。 Any performance penalties for casting should be dwarfed by the implementation of something(c) or something(b) , so don't overthink it unless the amount of types you try to cast to is really significant.强制转换的任何性能损失都应该与something(c)something(b)的实现相形见绌,所以不要想太多,除非你尝试转换的类型数量非常大。

If you are in control of A , B , C classes, see if you can rework your model so you don't need to do casting at all - make use of virtual methods as others suggest.如果您控制ABC类,请查看您是否可以返工您的 model ,因此您根本不需要进行铸造 - 使用其他人建议的虚拟方法。

There's not a tangible performance difference in using as or is .使用asis没有明显的性能差异。 What I've seen done in the framework however is that they provide an enum with a unique value for each type.然而,我在框架中看到的是它们为每种类型提供了一个具有唯一值的枚举。 This way you can switch on the type of the object.这样您就可以打开 object 的类型。

Expression trees does this, they have a property called NodeType that returns a value containing the type.表达式树就是这样做的,它们有一个名为NodeType的属性,它返回一个包含该类型的值。 This way you don't need to do more than one type test.这样您就不需要做不止一种类型的测试。

Then again, Marc just reminded me that these type of situations can sometimes be solved by using polymorphism correctly and that you're having this problem can be a sign of an underlying problem with the way you've written your classes.再一次,Marc 只是提醒我,有时可以通过正确使用多态性来解决这些类型的情况,并且您遇到此问题可能表明您编写类的方式存在潜在问题。

It seems to me that you should just use a virtual method.在我看来,您应该只使用虚拟方法。 It will result in efficient code that's more readable too.它将产生更易读的高效代码。

Usually the clean solution is a virtual method.通常干净的解决方案是虚拟方法。 But sometimes that's not possible.但有时这是不可能的。 In that case you could use a Dictionary<Type,Action> .在这种情况下,您可以使用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();

Note that this works only on the exact types, not on derived types.请注意,这仅适用于确切类型,不适用于派生类型。 So you might need to add some logic based on Type.IsAssignableFrom inside GetActionForType .因此,您可能需要在GetActionForType中添加一些基于Type.IsAssignableFrom的逻辑。

And obviously this implementation is not threadsafe.显然这个实现不是线程安全的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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