好吧,我现在整天都在喋喋不休地谈论这个想法,而且我已经达到了我承认我不知道的地方。我正在做的事情可能只是愚蠢而且有更好的方法,但这是我思考带给我的地方。
我试图使用通用方法在WinForms中加载表单:
protected void LoadForm<T>(ref T formToShow, bool autoLoaded) where T : FormWithWorker, new()
{
// Do some stuff
}
表单由ToolStripMenuItem加载(通过选择项目或使用Open 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 :(得分:12)
此问题通常通过强制转换为所有可能类型的公共基类或接口来解决。
在C#4中,您还可以将其分配给dynamic
变量以保存返回值并在其上调用任意方法。这些方法将被延迟绑定。但是,我希望尽可能坚持以前的解决方案。
答案 1 :(得分:5)
使用Type
并使用例如FormWithWorker formToLoad = (FormWithWorker)fi.GetValue(this);
if (formToLoad == null)
{
formToLoad =
(FormWithWorker)System.Activator.CreateInstance(Type.GetType("MyNamespace.MyFormType"));
}
的{{3}}会更好other overload
{{1}}
答案 2 :(得分:2)
根据你所拥有的,FormWithWorker
必须(至少)作为你实例化的类型的基类,所以你可以这样做:
FormWithWorker formToLoad = (FormWithWorker)fi.GetValue(this);
if (formToLoad == null)
{
formToLoad = (FormWithWorker)System.Activator.CreateInstance("MyAssemblyName", formType);
}
答案 3 :(得分:0)
虽然通用接口是解决此问题的一种方法,但接口对于所有场景都不实用。上面的决定是使用工厂模式(switch语句 - 具体类选择)或使用反射。有一个堆栈帖子可以解决这个问题。我相信您可以直接将此问题应用到您的问题中: