当我们需要动态的去加载程序集的时候(将对程序集的引用由编译时推移到运行时),反射是一种很好的选择。反射为.NET类型提供了高度的动态能力,包括:元数据的动态查询、绑定与执行、动态代码生成。常用的反射类型包含在System.Reflection和System.Reflection.Emit,反射包括程序集反射、类型反射、接口反射、类型成员反射。
vs.net反射的方法目前为止我知道的有两种:
1、通过Assembly类的方法CreateInstance()。方法名和前一样,不过它不是静态方法。Assembly是在System.Reflection命名空间中。
经典代码是petshop的工厂类实例化dal对象
public static PetShop.IDAL.IProduct CreateProduct()
{ string className = path + ".Product"; return (PetShop.IDAL.IProduct)Assembly.Load(path).CreateInstance(className); }
这里的path和className是通过web.config进行配置的,一个是路径,一个是要实例化的类名
private static readonly string path = ConfigurationManager.AppSettings["WebDAL"]; private static readonly string orderPath = ConfigurationManager.AppSettings["OrdersDAL"];
2、通过Activator类的CreateInstance()方法。这两种都是要加载dll进行实例化的。
有时候我们会这么做,直接去手动引用程序集。
Assembly assembly = Assembly.LoadFrom(@"e:\AutoFormFirstForm.dll"); Type type = assembly.GetType("FirstForm.Form1"); object obj = Activator.CreateInstance(type); Form formToShow = (Form)obj; formToShow.MdiParent = this; formToShow.Show();
上面的代码是通过Assembly加载了dll,并获取类型,然后通过Activator进行创建对象。
有时候我们不用加载dll,但是知道程序的类型也可以调用其构造函数进行实例化,有写IOC容器的实现就是这样实现的,比如Autofac,下面是模仿Autofac实现的控制反转。
public class Resolver { public Type RealType { get; set; } //用该委托来获取构造函数的参数实例 public Func<Type, object> GetParameterInstance { get; set; } public object GetInstance() { //取得Type的构造函数, 这里为了简便,默认使用最后一个,实际的Autofac默认会使用参数最长的一个 var constructors = RealType.GetConstructors(); var paramsInfos = constructors[constructors.Length - 1].GetParameters(); //准备构造函数的参数 var @params = new List<object>(); foreach (var parameterInfo in paramsInfos) { //根据类型,取的参数的实例 var tempPara = GetParameterInstance(parameterInfo.ParameterType); @params.Add(tempPara); } //调用构造函数构造对象 return constructors[0].Invoke(@params.ToArray()); } }
我们Autofac中要对容器中的某些类型进行实例化
var lister = _container.Resolve<MPGMovieLister>();
其中Resolve就是上面的类,在上面都有注释就不多说明了。