下面的代码不起作用,我想知道如何动态地将实例转换为在运行时确定的类型?
Convert.ChangeType()返回仍需要强制转换的Object。所有尝试Invoke()的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
答案 0 :(得分:4)
无法使用Type
值来确定表达式的类型。 (泛型类型参数与值不同,因为它们被编入类型系统。)
变量的值来自运行时代码执行,而表达式类型是编译时构造。毋庸置疑,编译发生在代码运行之前,因此使用变量进行强制转换是不可能的。
Reflection(albiet unwieldy)或dynamic
(基本上更容易使用 - 反射)允许调用任意方法或访问针对通用对象类型表达式的属性/字段 - 这偶尔会被称为“后期约束”。但是,调用操作的表达式的类型仍然是对象。
Interfaces可用于统一不同的类实现以进行适当的静态类型。然后可以将新创建的对象强制转换为适用的接口。就像其他表达式一样,类型是编译时构造(因此必须直接指定接口),但代码现在没有特定的类。
如果要创建一个系统,使这些“动态类”直接用于静态类型(C#)代码,并且接口可以保证或被约束到一个小集合,那么使用接口可能是最干净的方法:例如var myAction = (IMyAction)obj
。否则,回到动态访问 - 直接或在幕后。
答案 1 :(得分:3)
将您的变量定义为dynamic
并且它应该有效,我的意思是你仍然无法施放它但你可以访问你的方法:
dynamic obj = Activator.CreateInstance (type, new Object[]{ "argument" });
例如:
答案 2 :(得分: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);
答案 3 :(得分: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;
你也可以使用反射,但这相当麻烦,所以我不举一个例子。如果您具有在基本类型的不同子类型上定义的同名属性,但在基本类型上没有,则反射将非常有用。如果有许多子类型,则类型检查会变得很麻烦,因此反射可能是更好的方法。