电脑故障

位置:IT落伍者 >> 电脑故障 >> 浏览文章

Net反射在项目中的应用


发布日期:2018/3/16
 

反射的概念和基本原理msdn很详细这个文章主要说说反射在我的项目中的应用

反射用的比较多一个概念是程序集也可以认为就是dll类库程序集是所有类型的集合它还有一个重要的东西就是元数据JIT就是利用程序集的TypeRef和AssemblyRef等元数据来确定所引用的程序集及类型这些元数据包括名称版本语言文化和公钥标记等JIT就是根据这些信息来加载一个程序集到应用程序域中如果要自己加载一个程序集可以调用类型Assembly的LoadXXX系列方法从Assembly中可以读到这个dll中所以类类的继承接口类的方法属性字段事件等等

反射和接口

反射是在运行中动态的创建需要的类接口和接口的方法在编译的时候已经确定了接口的实现依赖他的继承类有了继承类接口才能实例化使用定义好的方法

反射就是把接口的实例化推迟到运行阶段所以反射一般和接口搭配使用

应用场景一单个接口对应多个实现

这个场景比较多而且在抽象工厂模式中我觉得用的很多典型的例子是数据读取层

一个项目可能用到SqlSeverAccessOrace或者TxtXML来当存取数据他们的方法都是统一比如增读等

这个时候就是定义一个IDataAccess接口这个接口定义了统一的方法读等然后分别用不同的实现类来继承这个接口

比如SqlServer类XmL类定义为SqlServerDataAccessXMLDataAccess他们都继承IDataAccess

在应用的时候项目可以通过简单的修改或者配置来使用Sqlserver或者XML数据库这个时候就可以使用反射来决定接口IDataAccess到底使用哪个实现类

抽象工厂模式中使用配置文件来设置使用Sqlserver还是XML数据实现类在配置文件中定义程序集和命名空间类名的信息这样通过修改配置文件就可以决定使用

Sqlserver还是XML数据实现类

public IDataAccess CreateDatAccess()

{

IDataAccess IDA =(IDataAccess)AssemblyLoad(配置节点程序集)CreateInstance(命名空间Sqlserver);

//IDataAccess IDA =(IDataAccess)AssemblyLoad(配置节点程序集)CreateInstance(命名空间XML);

return IDA;

}

应用场景二多个接口和多个实现类

这个例子的完全可以使用第一个场景的方案来解决但是由于接口多实现类实现起来比较复杂

这个例子说的是多个接口每个接口可能有一个实现类也可能有多个实现类

基本实现思路通过遍历bin下的文件夹得到dll信息把接口和对应的实现类组织到字典集合中然后根据一个接口信息就可以得到实现类实现接口的动态实例化

如果接口只有一个实现类就直接取得这个类如果接口有多个实现类那就传递一个类的名称来明确要求读取哪个类

具体实现为了更好的项目结构建立一个接口dll然后不同的接口对应不同的dll类库实现类的项目名称最好有个规格方便在遍历文件夹的时候读取特定名称的dll加快遍历速度

项目结构如图

在ConsoleApplicationFramework定义两个接口

public interface ICar { void Run(); } public interface IProduct { void OutputName(); }

在ConsoleApplicationImplProduct定义产品接口实现类

public class ProductA : IProduct { public void OutputName() { ConsoleWriteLine(Product A Name); } }

在ConsoleApplicationImplCar定义ICar实现类

public class AudiCar : ICar { public void Run() { ConsoleWriteLine(Audi Car Run); } } public class QQCar : ICar { public void Run() { ConsoleWriteLine(QQ Car Run); } }

然后开始重点代码部分

建立接口和实现类的对应关系保存到字典集合中

static Dictionary> dictionary = new Dictionary>();public static void GetInterfaceAndType() { string s = PathGetDirectoryName(AssemblyGetExecutingAssembly()Location); foreach (var file in DirectoryGetFiles(s ConsoleApplicationImpl*dll))//遍历程序下的类似命名规范的dll { var ass = AssemblyLoad(FileReadAllBytes(file));//得到程序集dll ConsoleWriteLine(assFullName); foreach (Type type in assGetTypes()Where(p=>pIsClass))//遍历程序集中类 { ConsoleWriteLine(typeFullName); Type[] interfaces = typeGetInterfaces();//该类继承的接口可能是多个接口 foreach (Type inter in interfaces)//建立接口和实现类的对应关系一个接口可能多个实现类 { if (!dictionaryContainsKey(inter)) { dictionaryAdd(inter new List()); } dictionary[inter]Add(type); } } } }

在根据接口读取实现类因为接口不同所以用泛型来实现

//specifiedImplType参数可以为空如果一个接口有多个实现类的时候需要特别指定使用哪个实现类 public static T GetImpTypeByInterface(string specifiedImplType = ) where T : class { Type interfaceType = typeof(T);//接口 if (dictionaryCount > && dictionaryContainsKey(interfaceType)) { Type implType = null; if (specifiedImplType == )//读字典集合中根据接口key得到实现类Type { implType = dictionary[interfaceType]First(); } else { implType = dictionary[interfaceType]Where(p => pName == specifiedImplType)FirstOrDefault(); } return ActivatorCreateInstance(implType) as T;//ActivatorCreateInstance该语法创建类的实例并且As 转换为T类型 } else { throw new Exception(没有继承对象); } }

最后测试运行

GetInterfaceAndType();//建立接口和实现类的对应集合 ICar iCar = GetImpTypeByInterface();//默认第一个实现类 iCarRun(); ICar iCar = GetImpTypeByInterface(QQCar);//指定实现类 iCarRun();

这样就可以直接根据接口类找到他对应的实现类

上一篇:NicPetShop 介绍并提供下载

下一篇:开发手记:共享软件注册程序编写实例(2)