2011-01-28 61 views
7

好吧,我现在整天都在想这个想法,而且我已经达到了我承认我只是不知道的部分。可能我所做的只是愚蠢的,还有更好的办法,但这是我思想给我带来的地方。如何将类型名称转换为字符串?

我试图用一个通用的方法来加载形式的WinForms:

protected void LoadForm<T>(ref T formToShow, bool autoLoaded) where T : FormWithWorker, new() 
{ 
    // Do some stuff 
} 

的形式由一个ToolStripMenuItem(通过项目的选择或使用打开Windows菜单项)加载。它们是延迟加载的,因此MDI父级中有表单的字段,但在需要它们之前它们为空。我有一个用于处理所有菜单项点击的ToolStripMenuItem_Click的常用方法。除了ToolStripMenuItem的名称匹配为它们对应的表单类名称选择的模式之外,该方法没有真正知道调用哪个表单的方法。因此,使用ToolStripMenuItem的名称,我可以确定被请求的表单类型的名称以及分配用于存储该表单引用的专用字段的名称。

使用这个,我可以使用硬编码类型和字符串匹配的增长/收缩switch语句来调用具有特定类型集的方法(不受欢迎),或者我可以使用Reflection获取字段并创建实例的类型。对我来说问题是,System.Activator.CreateInstance提供了一个ObjectHandler,它不能转换为我需要的类型。这里是我到目前为止的代码段:

string formName = "_form" + ((ToolStripMenuItem)sender).Name.Replace("ToolStripMenuItem", ""); 
string formType = formName.Substring(1); 

FieldInfo fi = this.GetType().GetField(formName, BindingFlags.NonPublic | BindingFlags.Instance); 

FormWithWorker formToLoad = (FormWithWorker)fi.GetValue(this); 
if (formToLoad == null) 
{ 
    formToLoad = (????)System.Activator.CreateInstance("MyAssemblyName", formType); 
} 

this.LoadForm(ref formToLoad, false); 
fi.SetValue(this, formToLoad); 

我知道,去为(????)类型的字符串名称,但在编译的时候,我不知道是什么类型,因为它改变。我尝试了很多方法来让这个演员/实例化工作,但都没有成功。我非常想知道是否有可能只知道这种类型的字符串。我尝试使用Type.GetType(string, string)来执行转换,但编译器不喜欢它。如果有人对如何动态加载表单有不同的想法,因为我只是在愚蠢地做,请让我知道。

+0

make formToLoad对象,并将其转换为LoadForm和SetValue点处的FormWithWorker? – asawyer 2011-01-28 19:14:25

回答

5

你会与需要Type和使用例如other overload更好Type.GetType(string)

FormWithWorker formToLoad = (FormWithWorker)fi.GetValue(this); 
if (formToLoad == null) 
{ 
    formToLoad = 
     (FormWithWorker)System.Activator.CreateInstance(Type.GetType("MyNamespace.MyFormType")); 
} 
12

此问题通常通过将所有可能类型转换为通用基类或接口来解决。

在C#4中,您也可以将其分配给dynamic变量以保存返回值并调用任意方法。方法将迟到。不过,我宁愿尽可能坚持以前的解决方案。

+0

投票表决。我使用一个界面做了非常类似的事情,它很好地工作。 – Chuck 2011-01-28 19:19:47

+0

我尝试了这种方法,但我遇到的问题是它最终分配的动态类型是基类而不是实际的类,所以当调用SetValue方法时,它抛出了一个类型转换异常。 – 2011-02-01 11:41:38

+0

@Joel作为其他答案指出,你应该使用返回对象本身的重载。显然,您使用的重载对于激活.NET远程对象很有用。 – 2011-02-01 12:01:47

2

根据你所拥有的,FormWithWorker必须(至少)作为基类你实例化的类型,那么你可以这样做:

FormWithWorker formToLoad = (FormWithWorker)fi.GetValue(this); 
if (formToLoad == null) 
{ 
    formToLoad = (FormWithWorker)System.Activator.CreateInstance("MyAssemblyName", formType); 
} 
0

虽然通用接口是解决这个的一种方式问题,接口对所有场景都不实用。上面的决定是与工厂模式(switch语句 - 具体类选择)一起使用还是使用反射。有一个堆栈文章解决了这个问题。我相信你可以直接在此适用于您的问题:

Method Factory - case vs. reflection

相关问题