2011-01-08 49 views
1

在vb.net中,可以設計一個能夠滿足多個約束的通用參數的函數。例如,可以有一個函數接受一個繼承自Control並實現IList的類作爲參數。這個函數可以在這樣一個對象上使用「Control」或「IList」方法,並且還可以將該對象傳遞給任何需要Control或IList的東西[請注意,選擇這個特定的組合是爲了便於簡單的例子,而不是特別的有用的組合]。多約束泛型函數調用如何實際工作?

 
    Sub CrossThreadAdd(Of T, U As {Control, IList(Of T)})(ByVal TheControl As U, ByVal NewThing As T) 
     If TheControl.InvokeRequired Then 
      TheControl.BeginInvoke(New Action(Of U, T)(AddressOf CrossThreadAdd), TheControl, NewThing) 
     Else 
      TheControl.Add(NewThing) 
     End If 
    End Sub 

此方法提供編譯時類型安全性;不需要在運行時可能失敗的演員陣容。另一種方法是將參數作爲Control或IList傳遞,並將函數轉換爲另一種方法。但是,如果傳遞的對象實際上不符合這兩個約束,那麼在運行時會失敗。

在什麼情況下使用像上面這樣的通用函數是好的,在什麼情況下最好能夠滿足兩個約束的對象都有一個新的接口,如IListableControl(Of T),它將包括一個將返回自身的控件屬性(作爲控件強制轉換),以及在什麼情況下最好有一個通用的自定義(T)接口,其中的任何實現者都應該提供一個「Self」屬性,以返回自身作爲T?

使用多約束泛型,可以做很多事情而不需要任何運行時類型轉換,但我不知道性能成本可能會如何。我嘗試編寫一個簡短的程序,在運行時生成65,536個不同的泛型類型,例如Foo(Foo的(Foo的(Foo的(Foo的(...(Blah的))...)))),它變得很慢,所以我可以告訴處理泛型所需的時間不是固定的,但是我不知道影響它的因素是什麼

回答

1

沒有運行時間開銷到普通函數的正常函數同樣,約束的數量在運行時絕對沒有方位 - 它是由編譯檢查。當然不同的事情,當你使用反射來訪問這些功能適用。

至於你的問題時,這種約束是有用的......

個人而言,我會說:經常。一個接口只應該模型一個關注。彙總界面(例如IListableControl)聽起來更像代碼味道(當然,這假設存在多種約束的泛型,否則它們實際上可能對提供類型安全性是必需的)。

+0

有沒有什麼辦法,而不使用聚合接口,將對象實例存儲在字段或集合中,以便稍後可以將其傳遞給多約束泛型函數?另外,我確定必須有* SOME *開銷 - 即使泛型具有類約束,泛型函數仍然知道傳入的類型,與參數類型無關(所以「U」可能是「 ListBox「,而TheControl可能是」FancyRainbowColoredListbox「的一個實例)。 – supercat 2011-01-08 17:55:25