1. Assembly中的类要从MarshalByRefObject继承,如果你想从你自己的类来继承,那么请选用interface或者继续研究其他解决方案。
namespace
Library
{
public class MyClass : MarshalByRefObject
{
}
}
其中MyClass的方法的返回值和参数必须是简单类型或者可序列化的。
2. 调用程序中,实现一个加载Assembly的辅助类,比如叫做LoadHelper,它也从MarshalByRefObject继承。在这个类里对Type的方法作一些封装,完成对MyClass中的方法的调用。
如:
Type的其他方法也可以在此进行封装。总而言之,把需要进行反射的代码都写在这里。封装的形式可以有多种方式,上面这个方法是在外部创建了一个对象实例,调用时传递给这个方法,再通过反射调用其方法。其实这种方式是效率比较低的,因为那个obj要在两个AppDomain之间传递,而跨AppDomain传递对象是要将这个对象序列化和反序列化的。所以为了改善效率,可以在这里临时创建对象。
比如:
public
object
InvokeInstanceMethodNotCachedAsm(
string
name,
string
assemblyFile,
string
typeName,
object
[] paras)
{
object obj;
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
Assembly asm = Load(assemblyFile);
obj = asm.CreateInstance(typeName);
return obj.GetType().InvokeMember(name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod, null, obj, paras);
}
甚至还可以采取将Assembly缓存的机制,这样调用起来速度更快。
3.
调用程序中加载和卸载AppDomain:
static
void
Load()
{
AppDomainSetup setup = new AppDomainSetup();
setup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
setup.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
setup.ShadowCopyFiles = "true";
setup.ShadowCopyDirectories = "需要动态加载的Assembly所在文件夹";//影像副本目录
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
setup.ApplicationName = "Dynamic";
// Set up the Evidence
Evidence baseEvidence = AppDomain.CurrentDomain.Evidence;
Evidence evidence = new Evidence(baseEvidence);
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
// Create the AppDomain
appDomain = AppDomain.CreateDomain("newDomain", evidence, setup);
loader = (LoadHelper)appDomain.CreateInstanceAndUnwrap("程序的AssemblyName", "那个辅助类的全名");
}
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
static
void
Unload()
{
AppDomain.Unload(appDomain);
}
在这里,有三点是关键,一是创建一个新的AppDomain,二是让这个新的AppDomain允许使用影像副本文件,三是要把影像副本目录设为非主程序所在文件夹。
这是因为.Net不允许卸载一个已加载的Assembly,除非卸载整个AppDomain,允许使用影像副本,.Net就把要加载的Assembly复制到另一个文件夹(在用户配置文件夹中),但程序所在文件夹中的Assembly并不被复制。
4.创建对象实例
object obj = appDomain.CreateInstanceFromAndUnwrap("Assembly文件名含路径", "类名");
这样就创建了一个指定的类的实例,但是,不要试图对这个obj进行反射,对这个obj进行反射,不能得到其实际类型的信息,因为在主程序文件夹中没有部署那个Assembly,而只会得到其已部署的基类和接口类型,只能对这些类型进行操作。
5. 调用
如果在主程序的AppDomain中加载了所创建的对象的基类或者接口类型,那么可以调用这些类型的相关成员。
如果没有,那么就通过调用LoadHelper中的相关方法来调用。
6.卸载与替换
程序运行起来后,Assembly所在文件夹中的这个已加载的Assembly文件,是可以被删除的,因为实际上加载的那个文件是其副本,删除之后程序照样运行,而替换一个新的,也不会起作用。只有当调用上面的Unload和Load方法,卸载和重新加载后,新的Assembly才会起作用。
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
}
}
2. 调用程序中,实现一个加载Assembly的辅助类,比如叫做LoadHelper,它也从MarshalByRefObject继承。在这个类里对Type的方法作一些封装,完成对MyClass中的方法的调用。
如:
//name:方法名
public
object
InvokeMethod(
string
name,
object
obj,
object
[] paras)
{
return obj.GetType().InvokeMember(name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod, null, obj, paras);
}
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)
Type的其他方法也可以在此进行封装。总而言之,把需要进行反射的代码都写在这里。封装的形式可以有多种方式,上面这个方法是在外部创建了一个对象实例,调用时传递给这个方法,再通过反射调用其方法。其实这种方式是效率比较低的,因为那个obj要在两个AppDomain之间传递,而跨AppDomain传递对象是要将这个对象序列化和反序列化的。所以为了改善效率,可以在这里临时创建对象。
比如:
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
甚至还可以采取将Assembly缓存的机制,这样调用起来速度更快。
3.
调用程序中加载和卸载AppDomain:
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6810355c2f78c12e91b7997a8e8c583a.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/6a9c071a08f1dae2d3e1c512000eef41.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/0196c3df5ea9e936f21e9932cca91014.gif)
这是因为.Net不允许卸载一个已加载的Assembly,除非卸载整个AppDomain,允许使用影像副本,.Net就把要加载的Assembly复制到另一个文件夹(在用户配置文件夹中),但程序所在文件夹中的Assembly并不被复制。
4.创建对象实例
object obj = appDomain.CreateInstanceFromAndUnwrap("Assembly文件名含路径", "类名");
这样就创建了一个指定的类的实例,但是,不要试图对这个obj进行反射,对这个obj进行反射,不能得到其实际类型的信息,因为在主程序文件夹中没有部署那个Assembly,而只会得到其已部署的基类和接口类型,只能对这些类型进行操作。
5. 调用
如果在主程序的AppDomain中加载了所创建的对象的基类或者接口类型,那么可以调用这些类型的相关成员。
如果没有,那么就通过调用LoadHelper中的相关方法来调用。
6.卸载与替换
程序运行起来后,Assembly所在文件夹中的这个已加载的Assembly文件,是可以被删除的,因为实际上加载的那个文件是其副本,删除之后程序照样运行,而替换一个新的,也不会起作用。只有当调用上面的Unload和Load方法,卸载和重新加载后,新的Assembly才会起作用。