2014-01-25 145 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