簡體   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