发文章
发文工具
撰写
网文摘手
文档
视频
思维导图
随笔
相册
原创同步助手
其他工具
图片转文字
文件清理
AI助手
留言交流
反射的概念和基本原理msdn很详细,这个文章主要说说反射在我的项目中的应用
反射用的比较多一个概念是程序集,也可以认为就是dll类库,程序集是所有类型的集合,它还有一个重要的东西就是元数据。JIT就是利用程序集的TypeRef和AssemblyRef等元数据来确定所引用的程序集及类型,这些元数据包括名称、版本、语言文化和公钥标记等,JIT就是根据这些信息来加载一个程序集到应用程序域中。如果要自己加载一个程序集,可以调用类型Assembly的LoadXXX系列方法。从Assembly中可以读到这个dll中所以类,类的继承接口,类的方法,属性,字段,事件等等。
反射和接口
反射是在运行中动态的创建需要的类,接口和接口的方法在编译的时候已经确定了,接口的实现依赖他的继承类,有了继承类,接口才能实例化使用定义好的方法。
反射就是把接口的实例化推迟到运行阶段。所以反射一般和接口搭配使用。
应用场景一:单个接口对应多个实现
这个场景比较多,而且在抽象工厂模式中我觉得用的很多,典型的例子是数据读取层。一个项目可能用到SqlSever,Access,Orace或者Txt,XML来当存取数据,他们的方法都是统一,比如增,删,修,读等
这个时候就是定义一个IDataAccess接口,这个接口定义了统一的方法,增,删,修,读等,然后分别用不同的实现类来继承这个接口,
比如SqlServer类,XmL类,定义为SqlServerDataAccess,XMLDataAccess,他们都继承IDataAccess
在应用的时候项目可以通过简单的修改或者配置来使用Sqlserver或者XML数据库,这个时候就可以使用反射来决定接口IDataAccess到底使用哪个实现类
抽象工厂模式中使用配置文件来设置使用Sqlserver还是XML数据实现类。在配置文件中定义“程序集和命名空间类名”的信息,这样通过修改配置文件就可以决定使用
Sqlserver还是XML数据实现类
public IDataAccess CreateDatAccess()
{
IDataAccess IDA =(IDataAccess)Assembly.Load("配置节点程序集").CreateInstance("命名空间.Sqlserver");
//IDataAccess IDA =(IDataAccess)Assembly.Load("配置节点程序集").CreateInstance("命名空间.XML");
return IDA;
}
应用场景二:多个接口和多个实现类
这个例子的完全可以使用第一个场景的方案来解决,但是由于接口多,实现类,实现起来比较复杂
这个例子说的是多个接口,每个接口可能有一个实现类,也可能有多个实现类。
基本实现思路通过遍历bin下的文件夹,得到dll信息,把接口和对应的实现类组织到字典集合中,然后根据一个接口信息就可以得到实现类,实现接口的动态实例化
如果接口只有一个实现类就直接取得这个类,如果接口有多个实现类那就传递一个类的名称来明确要求读取哪个类
具体实现,为了更好的项目结构,建立一个接口dll,然后不同的接口对应不同的dll类库,实现类的项目名称最好有个规格,方便在遍历文件夹的时候读取特定名称的dll,加快遍历速度。
项目结构如图:
在ConsoleApplication2.Framework定义两个接口
public interface ICar { void Run(); } public interface IProduct { void OutputName(); }
在ConsoleApplication2.Impl.Product定义产品接口实现类
public class ProductA : IProduct { public void OutputName() { Console.WriteLine("Product A Name..."); } }
在ConsoleApplication2.Impl.Car定义ICar实现类
public class AudiCar : ICar { public void Run() { Console.WriteLine("Audi Car Run..."); } } public class QQCar : ICar { public void Run() { Console.WriteLine("QQ Car Run..."); } }
然后开始重点代码部分
1.建立接口和实现类的对应关系,保存到字典集合中
static Dictionary<Type, List<Type>> dictionary = new Dictionary<Type, List<Type>>();public static void GetInterfaceAndType() { string s = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); foreach (var file in Directory.GetFiles(s, "ConsoleApplication2.Impl.*.dll"))//遍历程序下的类似命名规范的dll, { var ass = Assembly.Load(File.ReadAllBytes(file));//得到程序集dll Console.WriteLine(ass.FullName); foreach (Type type in ass.GetTypes().Where(p=>p.IsClass))//遍历程序集中类 { Console.WriteLine(type.FullName); Type[] interfaces = type.GetInterfaces();//该类继承的接口,可能是多个接口 foreach (Type inter in interfaces)//建立接口和实现类的对应关系,一个接口可能多个实现类 { if (!dictionary.ContainsKey(inter)) { dictionary.Add(inter, new List<Type>()); } dictionary[inter].Add(type); } } } }
在根据接口读取实现类,因为接口不同,所以用泛型来实现
//specifiedImplType参数可以为空,如果一个接口有多个实现类的时候,需要特别指定使用哪个实现类 public static T GetImpTypeByInterface<T>(string specifiedImplType = "") where T : class { Type interfaceType = typeof(T);//接口 if (dictionary.Count > 0 && dictionary.ContainsKey(interfaceType)) { Type implType = null; if (specifiedImplType == "")//读字典集合中根据接口key得到实现类Type { implType = dictionary[interfaceType].First(); } else { implType = dictionary[interfaceType].Where(p => p.Name == specifiedImplType).FirstOrDefault(); } return Activator.CreateInstance(implType) as T;//Activator.CreateInstance该语法创建类的实例,并且As 转换为T类型 } else { throw new Exception("没有继承对象"); } }
最后测试运行
GetInterfaceAndType();//建立接口和实现类的对应集合 ICar iCar = GetImpTypeByInterface<ICar>();//默认第一个实现类 iCar.Run(); ICar iCar = GetImpTypeByInterface<ICar>(“QQCar”);//指定实现类 iCar.Run();
来自: 昵称10504424 > 《工作》
0条评论
发表
请遵守用户 评论公约
什么是反射、反射可以做些什么
WriteLine(''请输入对象类名'');string className = Console.ReadLine();Console.WriteLine(''请输入要执行的...
.Net core 的热插拔机制的深入探索,以及卸载问题求救指南.
Load和LoadUnmanagedDll函数实际上是给开发者手动加载程序集使用的, 自动加载应放到Resolving和ResolvingUnmanagedDll事件中 原因是,这样的加载顺序不会导致项目的程序集覆盖插件的程序集,造成程序集加...
C#反射
WriteLine("This''''''''s t.type={0},w.type={1}, x.type={2},t:{3},w:{4},x:{5}", t...
【C#】反射的用法及效率对比
C# 反射的基本使用方法
//泛型类+泛型函数的反射使用 Type typeG = assembly.GetType("dll名称.类名 `1"); //获取类型信息 一个泛...
(9)程序集的加载和反射
GetType 方法返回表示【实例类型】的 Type 对象。h) MakeGenericType 方法返回 Type 对象,该对象表示构造泛型类型,如果该对象...
DotNet动态创建类
'' 构造DLL文件的全路径 Dim dllName As String = String.Format("{0}\{1}.dll", _ DLLPath, _ sourceFile.Name.Replace(".", "_"))MapPath("~/App_Code/C...
.Net应用程序的执行环境(CLR关于Assembly的搜索算法)
如果GAC里面的NetLibaryTest.dll文件放到GAC中去了,则最后NetVersionTest.exe首先会从GAC中里面去寻找,即最后输出:”GAC”如果NetLibar...
C#Assembly详解
一些情况下,你可以发现多个应用程序需要使用共享的assembly而不只是使用他们自己的,对这种情况,你可以在全局assembly缓存(译者:Global Assembly Cache,这个翻译有点不伦不类,大家明白就好)中管理...
微信扫码,在手机上查看选中内容