无法转换从DLL文件加载的控件 [英] Cannot cast control loaded from DLL file

查看:56
本文介绍了无法转换从DLL文件加载的控件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好的,所以我试图为我的项目获得一个applet插件样式编辑器界面,我需要能够转换一个在主项目和外部applet模板中都引用的自定义类.我可以使用Assembly加载dll文件并获取UserControl,但该类中有属性和方法.没有InvalidCastException,我无法将类强制转换为自定义UserControl.这是代码:

Okay, so I am trying to get an applet plugin style editor interface for a project of mine and I need to be able to cast a custom class that is referenced in both the main project and in the external applet template. I can use Assembly to load the dll file and get the UserControl out, but there are properties and methods in the class. I cannot cast the class to the custom UserControl without an InvalidCastException. Here is the code:

//Get Name
string AppletName = AppletPaths[i].Replace(Application.StartupPath + "\\Applets\\", "");
//Get Assembly
Assembly asm = Assembly.LoadFile(AppletLocation);
Type type = asm.GetType("Example.AppletUI");

var obj = Activator.CreateInstance(type);
Example.AppletUI applet = (Example.AppletUI)obj;

推荐答案

这段代码很难讨论.您是否在Debugger下运行它?首先,只看第一行.您用空字符串替换某些目录.为什么?! (顺便说一句,不要使用",请使用string.Empty.)那么AppletName的目的是什么?

现在,不好的事情是使用类名的GetType.您如何支持它?如果您决定更改班级名称怎么办?当然,您将需要在多个地方进行更改,这是一个很大的编程禁忌. (如果您不了解,请阅读 http://en.wikipedia.org/wiki/Don%27t_repeat_yourself [ ^ ].)这里的主要问题是:如果类型名称拼写错误,编译器将无法帮助您检测到问题.这就是为什么必须避免使用任何立即常量的原因,尤其是字符串.具有良好的编程风格,很容易避免. (当然,我不计算一些在各处使用的常量,例如0、1和null.)

此方法并不是为激活插件实现而专门设计的.如果有一个很好的方法来查找和激活插件类而根本没有任何常量,那么为什么要这样做呢?这种方法非常简单:定义插件应实现的某些接口.宿主应用程序可以加载程序集并检查所有满足以下条件的顶级类:此类应实现所需的插件接口和无参数构造函数(或某些必需签名的构造函数).

我还采取了另一步骤以避免测试所有类型:我定义了一个程序集级属性,该属性用于声明此程序集在类A中(例如,使用typeof )".宿主应用程序使用Reflection仅检查一个类(或一组类,因为同一程序集可用作一种以上类型的插件).要查看有关如何应用程序集级属性的示例,请查看AssemblyInfo.cs文件.主机应用程序应检查每个插件程序集和插件实现类型的一致性.如果该插件不符合要求的标准(例如仅一个实现,至少在实现上存在,实现与声明属性之间的匹配等),并且在出现不一致时可以采取相应措施,这可以被视为警告或致命错误.

我在过去的解决方案中进一步详细介绍了该技术.请参阅:
创建使用可重载插件的WPF应用程序... [ ^ ],
AppDomain拒绝加载程序集 [使用CodeDom生成代码 [创建使用可重载插件的WPF应用程序... [ ^ ].

这里说明了一个简单的情况:动态加载用户控件 [ ^ ].

对于可能比您需要的情况先进得多的情况,我深表歉意.问题出在可重装的插件中​​.由于.NET不允许卸载已加载的程序集,因此应使用应用程序域,并且应跨应用程序域边界使用IPC.如果只需要加载插件而无需在运行时卸载它们,则可以忽略此方面.

—SA
This code is too bad to discuss. Did you run it under Debugger? First, just look at the first line. You replace some directory with empty string. Why?! (By the way, don''t use "", use string.Empty.) What''s the purpose of AppletName then?

Now, a bad thing is using GetType by the class name. How can you support it? What if you decide to change the class name? You will certainly need to change it in more than one place, which is a big programming no-no. (If you don''t understand it, read http://en.wikipedia.org/wiki/Don%27t_repeat_yourself[^].) Main problem here is this: if the type name is misspelled, compiler won''t help you to detect the problem. That''s why any immediate constants should be avoided by all means, especially string. With good programming style, it''s easy to avoid. (Of course I don''t count some constants used everywhere like 0, 1 and null.)

This method is not really designed for activation of plug-in implementations. Why doing this if there is a nice method to find and activate plug-in class without any constants at all. This approach is very simple: define some interface which a plug-in should implement. The host application can load an assembly and check all top-level classes which meet the following criteria: such class should implement the required plug-in interface and a parameterless constructor (or a constructor of some required signature).

I make one more step to avoid testing all types: I define an assembly-level attribute which is used to claim "this assembly implements the plug-in interface IPlugin (for example) in the class A (using typeof)". The host application uses Reflection to check up just one class (or a set of classes, because the same assembly could be uses as a plug-in of more than one type). To see an example on how to apply assembly-level attribute, look at you AssemblyInfo.cs file. The host application should checkup each plug-in assembly and plug-in implementation type for consistency. If the plug-in does not meet required criteria (such as only one implementation, existence of at least on implementation, match between implementation and claim attribute, etc.) and act accordingly if there is a inconsistency which could be considered as a warning or a fatal error.

I described this technique in further detail in my past solutions. Please see:
Create WPF Application that uses Reloadable Plugins...[^],
AppDomain refuses to load an assembly[^].

For more special uses of plug-ins, see:
code generating using CodeDom[^],
Create WPF Application that uses Reloadable Plugins...[^].

A simple case is explained here: Dynamically Load User Controls[^].

I apologize for the cases which may be much more advanced then you might need. The problem is in reloadable plug-ins. As unloading of a loaded assembly is not allowed by .NET, Application Domains and work with IPC across the Application Domain boundaries should be used. If you only need to load plug-ins without a need to unload them during run time, you can ignore this aspect.

—SA


这篇关于无法转换从DLL文件加载的控件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆