2014-01-25 139 views
1

下面的代碼將不起作用,我想知道如何動態地將實例轉換爲在運行時確定的類型?使用類型變量強制轉換

Convert.ChangeType()返回一個仍然需要轉換的對象。因此,所有嘗試調用()GetConstructor()或Activator.CreateInstance(),見下文。在某些時候,我需要明確地投入代碼,我希望避免它或儘可能地推出它。

Type type = Type.GetType ("RandomChildClass"); 
Object obj = Activator.CreateInstance (type, new Object[]{ "argument" }); 
var instance = (type)obj; 

我知道我可以創建接受< T>的方法,但我仍然不知道如何與動態隨機型 Casting a variable using a Type variable

+2

你在施放後想用'instance'做什麼? – JaredPar

+0

只是將其添加到基類型列表 – user2994682

回答

3

這是不可能使用Type確定類型的表達式的。 (因爲它們被編入的類型系統泛型類型參數比的值不同。)

的變量的值是從代碼執行運行時間,而表達類型是編譯時構造。不用說,編譯發生在代碼運行之前,因此使用變量進行轉換是不可能的。

Reflection(albiet笨重)或dynamic(其基本上是比較容易使用的反射)允​​許調用任意方法或訪問屬性/對一個通用類型的對象表達字段 - 這是偶爾refered爲「後期綁定」 。但是,調用操作的表達式類型仍然是對象。

Interfaces可用於統一不同的類實現以進行正確的靜態類型。然後新創建的對象可以轉換爲適用的接口(S)是必需的。就像其他表達式一樣,這個類型是編譯時間構造(因此必須直接指定該接口),但是代碼現在不受特定類的限制。

如果創建一個系統以便這些「動態類」直接用於靜態類型(C#)代碼,並且可以保證接口或將其限制爲一個小集合,那麼使用接口可能是最乾淨的方法:例如var myAction = (IMyAction)obj。否則,回到動態訪問 - 直接或在幕後。

+0

我的希望是動態地填充演員陣容中的((IMYACTION))部分,但從你的解釋來看,它完全不可能出現。那是對的嗎? – user2994682

+0

做了一些更新以上澄清。 – user2994682

+0

@ user2994682這是正確的。這是不可能的,出於同樣的原因。 – user2864740

2

定義您的變量調用它的同樣的問題作爲dynamic,它應該工作,我的意思是你仍然可以不投,但你可以訪問你的方法:

dynamic obj = Activator.CreateInstance (type, new Object[]{ "argument" }); 

例如:

enter image description here

+0

是否有可能不使用動態?我收到編譯錯誤 – user2994682

+0

作了一些更新以上澄清。 – user2994682

3

根據您的評論,您正在嘗試將其添加到List<SomeDynamicClass>。我的第一個想法是,如果你不能靜態訪問SomeDynamicClass,那麼我很好奇你是怎麼做的,或者爲什麼你有一個List<SomeDynamicClass>。這聽起來像代碼會好得多List<object>List<dynamic>而不是。

如果你被限制爲List<SomeDynamicClass>那麼它聽起來像你應該直接跳到使用反射來調用Add方法

var listType = theList.GetType(); 
var method = listType.GetMethod("Add"); 
method.Invoke(theList, obj); 
+0

我很抱歉產生困惑,我真的只想要一種動態投射到特定的孩子班的方式。之後發生了一個簡單的添加基地名單將工作。 – user2994682

+0

如果我構造一個子對象(通過調用構造函數)並將其轉換爲父對象,稍後當我想使用它時,我仍然需要將其明確地轉換爲子對象。但是如果我能夠保持它的類型,將它添加到基類的列表中,在使用中它仍然保留它自己的類型(而不是基類),我在這個假設中錯了嗎? – user2994682

+0

做了一些更新以上澄清。 – user2994682

1

如果以靜態知道基類的類型,強制轉換爲該類型。例如:

void AddToList(List<Control> list, string typeName) { 
    var control = (Control)Activator.CreateInstance(typeName); 
    list.Add(control); 
} 

然後

var list = new List<Control>(); 
AddToList(list, "Button"): 
AddToList(list, "Label"): 
AddToList(list, "ListBox"): 

如果需要以後做一些類型特異性,可以測試的類型和投:

foreach (Control child in list) 
    DoSomethingWithThe(control); 

void DoSomethingWithThe(Control control) 
{ 
    Button button = control as Button; 
    if (button != null) 
    { 
     button.Click += Button_Click; 
     return; 
    } 

    Label label = control as Label; 
    if (label != null) 
    { 
     label.MouseOver += Label_MouseOver; 
     return; 
    } 
    //... etc. 
} 

或者使用OfType方法:

foreach (Button button in list.OfType<Button>()) 
    button.Click += Button_Click; 

foreach (Label label in list.OfType<Label>()) 
    label.MouseOver += Label_MouseOver; 

您還可以使用反映離子,但這相當麻煩,所以我不會舉一個例子。如果您有一個與在基類型的不同子類型上定義的名稱相同的屬性,但不在基類型上,則反射會很有用。如果有許多子類型,類型檢查會變得麻煩,所以反射可能是更好的方法。

+0

謝謝,我想盡量保持孩子的類型。可能嗎? – user2994682

+0

做了一些更新以上澄清。 – user2994682

+0

@ user2994682在user2864740回答時,不,在編譯時不可能保留子的靜態類型。但是,子對象始終保持其運行時間。例如,這段代碼產生一個包含一個字符串和一個盒裝int的列表:var objects = new List {「One」,2}'。這些對象將始終是一個字符串和一個盒裝的int。如果您需要在從列表中檢索特定類型的子項時執行類型特定的操作,請測試類型並進行投射(可能使用Linq'OfType'方法),否則使用反射。我會添加幾個例子。 – phoog