2009-07-11 125 views
1

請看下面的情況。我有一個XML文檔如下,動態鑄造C#

<Form> 
    <Control Type="Text" Name="FirstName" /> 
    <Control Type="DateTime" Name="DateOfBirth" /> 
    <Control Type="Text" Name="PlaceOfBirth" /> 
</Form> 

我有一個稱爲控制與單個抽象方法被稱爲過程需要的HttpRequest的單個參數的抽象類。我還有兩個派生自Control的類,稱爲TextControl和DateTimeControl。 Text和DateTime都會覆蓋Process方法以提供它們自己的實現。

我也有一個Form類,它有一個Process方法接受一個HttpRequest類型的參數,一個構造函數接受一個XmlDocument類型的參數。

創建Form的新實例,並通過XmlDocument參數傳入上述Xml(我們如何從字符串獲取到XmlDocument是無關緊要的)。然後,我調用剛剛創建的Form I實例的Process方法,並按預期方式傳入類型爲HttpRequest的參數。

目前爲止都很好。現在回到這個問題上。

爲了使控件的處理可擴展,我希望能夠將類映射爲控件類型。

例如。

Form.RegisterControl("Text", Text) 
Form.RegisterControl("DateTime", DateTimeControl) 

在形式的過程方法我想itterate在文檔中的每個控制節點(如何做,這是再次不相關)和實例化,其基於註冊的類相匹配的類型的類的一個實例通過我們的RegisterControl方法。我可以在這個階段指定它們來自Control,但不能明確指定它們的類型。因爲它們都是從Control派生的,所以我想調用我知道將實現的Process方法。

這甚至可能嗎?如果是這樣,我會怎麼做呢?

回答

4

(這個答案是在某些方面兩個不同的答案,這取決於你的問題的意思。希望其中的一個一部分是有幫助的,反正:)


也許最好的辦法是通過在一個參數中可以用來在正確的時間創建新的控件。如果您使用C#3,這很簡單,只要:

Form.RegisterControl("Text",() => new Text()) 

或者,你可以把一個通用的方法有兩個限制:一個,作爲一個控制,以及一個用於具有參數的構造函數。

public void RegisterControl<T>(string name) where T : Control, new() 

然後調用它:

Form.RegisterControl<Text>("Text"); 
Form.RegisterControl<DateTimeControl>("DateTime"); 

RegisterControl必須記住它使用任何存儲typeof(T),但至少它可能是有理由相信Activator.CreateInstance(Type)將工作以後 - 和你」 d有編譯時檢查。我個人喜歡第一種形式的靈活性 - 如果你傳遞一個委託,它可以選擇使用單例,或者可能是一些內部甚至私有構造函數(取決於它從哪裏調用)。你也可以使用一個委託歷時適當的數據,太:

Form.RegisterControl("Text", data => new Text(data)); 

你不能表達那種構造與通用約束,這將是比較硬反正以後調用。


編輯:這可能是我自己和Mehrdad誤解了這個問題。根據控制類型,你是否有不同的過載RegisterControl?如果是這樣,那麼在執行時直接調用正確的過載的唯一方法是使用反射或在C#4中使用動態類型。

另一種替代方法是使用雙派遣 - 在控件本身中放置一個方法知道如何使用表單註冊自己。這將在接口或基類中指定,但在具體子類中覆蓋。所以,你的代碼是目前:

Form.RegisterControl("Text", control); 

將成爲:

control.RegisterWith(Form, "Text"); 

然後可以調用沒有問題正確的過載。

基本上你需要記住,重載解析是在編譯時執行的,但重載解析是在執行時執行的 - 所以如果你想使某些動態變爲動態,請嘗試使用多態來處理它。

+0

謝謝喬恩!第一個答案應該是正確的(你假設正確)。我現在正在破解它! – 2009-07-11 23:14:56