c#动态加载dll并调用dll中类的方法
当然,这里指的是托管的dll与托管的方法,实际上用到的东西大部分是在反射(reflecting)命名空间里头的。
用途或许广泛吧,我不是很确信,但这个是在运行期绑定的,那么就不会有编译期绑定那么僵硬……但也没有编译期绑定那么简单。
可以用于做插件之类的。
先是一个接口,实现了这个接口的类被认为是合法的,可以被载入的……
namespace gp { public delegate void DoWhat(); public interface IInterface { string GetName(); DoWhat dowhat { get; set; } } }
很简单的接口,一个是用于判断做什么的函数,另外一个,则是一个方法的委托,做什么。
然后,我们新建一个项目,弄个类实现这个接口:
namespace gp { public delegate void DoWhat(); public interface IInterface { string GetName(); DoWhat dowhat { get; set; } } }
在构造函数里头将委托加了一个项,当执行那个委托的时候就会执行这个函数。
现在是重要的一个部分,代码难度不大~~
新建一个windows application,然后在窗体上头拖一个panel,这个是为了动态加载后将操作按钮放上去的。。不过可能会重叠,建议考虑用flowlayoutpanel,这个会自动重排以满足个数,anyway,无所谓,反正是为了阐述概念。
private void Form1_Load(object sender, EventArgs e) { var plugindir = System.IO.Directory.GetParent(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName).CreateSubdirectory("startup"); foreach (var filesInPlugin in plugindir.GetFiles()) { if (filesInPlugin.Extension.ToLower() == ".dll") { Assembly dllFromPlugin = Assembly.LoadFile(filesInPlugin.FullName); foreach (var dllModule in dllFromPlugin.GetLoadedModules()) { foreach (var typeDefinedInModule in dllModule.GetTypes()) { if (typeDefinedInModule.GetInterfaces().Contains(typeof(gp.IInterface))) { if (typeDefinedInModule.IsClass) { var itemGet = System.Activator.CreateInstance(typeDefinedInModule) as gp.IInterface; LinkLabel ll_now = new LinkLabel(); ll_now.Text = itemGet.GetName(); ll_now.Click += (a, b) => { if (itemGet.dowhat != null)itemGet.dowhat(); }; panel1.Controls.Add(ll_now); } } } } } } }
一个不难看懂的代码,先是指定插件文件夹的位置,要是没有就创建一个。然后遍历里头为dll类型的文件,再试图转载这个文件——实际情况下,这里需要加 try...catch,因为谁也不知道你加载的dll文件倒是是不是合法的dll文件,然后遍历里头的模块,再遍历模块里头的定义的类型——可能是类、 interface、枚举等等等等,很多很多,取得这个玩意儿的集成的interface,再判断是不是包含我们的interface。(也就是说,包含了这个interface就算是合法的插件类)
如果包含了的话,判断这是不是一个类,因为接口也可以在其他的东西里头被继承,比如另一个接口等等,而其他这些情况对我们来说毫无意义。
然后,我们动态创建这个类的实例—— System.Activator.CreateInstance,并且进行转换,转换为继承的接口,现在开始就是强类型操作了。我这里做的操作是生成一个linklabel,并且设置名称和按下执行的方法。。。大概就是这样,以上。