一直以来,我们都在用C#编写程序,编写程序的时候,我们用到继承、多态、接口以及泛型,我们也都明白子类可以继承抽象类,并能够重写父类的抽象方法,可是大家是否想过,如下几个问题:

  1、凡树必有根和叶,类的继承也如此,如何通过程序集查找所有继承父类的之类的程序集名称?

  2、如果程序B被其他程序调用,如何通过程序集查询调用B的所有程序?

  3、如何查询当前项目通过添加引用了哪些程序集?

一、查询

查询继承父类的程序集合BaseType

  .NET的程序集对象Assembly有个属性BaseType,来返回当前程序集的基础类型,默认是Object。通过该属性可以判断某个程序集是否是继承了某个父类;

程序集B被A程序引用,获取A程序集的信息GetCallingAssembly

  .NET的程序集对象Assembly有个方法GetCallingAssembly获取当前程序集被调用的上级程序集的信息;

查找当前项目的程序集GetAssemblies

  查找当前项目所有程序集的方法System.AppDomain.CurrentDomain.GetAssemblies();

实例化对象

  通过程序集GetType()获取程序集的数据类型,通过Activator.CreateInstance(type) 便可创建响应的实例对象;

整体使用的代码如下:BaseService是所有服务类的基类

List<Type> TypeItemList = new List<Type>();
//var ResultTypeList = Assembly.GetEntryAssembly();
//if (ResultTypeList == null)
//{
// ResultTypeList = Assembly.GetCallingAssembly();
// var ItemList = ResultTypeList.GetReferencedAssemblies().Where(p => p.GetType() == typeof(BaseService));
//}
Assembly[] AssbyCustmList = System.AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly assItem in AssbyCustmList)
{
TypeItemList.AddRange(assItem.GetTypes().Where(x => x.BaseType == typeof(BaseService)).ToList());
}
//IEnumerable<Type> TypeItemList = CurType.Assembly.GetExportedTypes().Where(x => x.BaseType == typeof(BaseService)).ToList();
//IEnumerable<Type> TypeItemList = ResultTypeList.GetTypes().Where(x => x.BaseType == typeof(BaseService)).ToList();
BaseService TarService = null;
foreach (Type typeitem in TypeItemList)
{
if (_Reporttory.Count(p => p.GetType() == typeitem) == )
{
TarService = (Activator.CreateInstance(typeitem) as BaseService);
}
else
{
TarService = _Reporttory.First(p => p.GetType() == typeitem);
}
TarService.Start();
}

测试代码

 static void ShowAssemblyDetail(Assembly assembly, string name = "")
{
Console.WriteLine("============ \n");
Console.WriteLine("FullName:" + assembly.FullName);
Console.WriteLine("CodeBase:" + assembly.CodeBase);
Console.WriteLine("EscapedCodeBase:" + assembly.EscapedCodeBase);
Console.WriteLine("GlobalAssemblyCache:" + assembly.GlobalAssemblyCache);
Console.WriteLine("HostContext:" + assembly.HostContext);
Console.WriteLine("ImageRuntimeVersion:" + assembly.ImageRuntimeVersion);
Console.WriteLine("IsDynamic:" + assembly.IsDynamic);
Console.WriteLine("IsFullyTrusted:" + assembly.IsFullyTrusted);
Console.WriteLine("Location:" + assembly.Location);
Console.WriteLine("ReflectionOnly:" + assembly.ReflectionOnly);
Console.WriteLine("SecurityRuleSet:" + assembly.SecurityRuleSet);
}

二、加载方法

关于.NET中的反射,常用的有三个方法:
Assembly.Load()
Assembly.LoadFrom()
Assembly.LoadFile()

1:Assembly.Load()

  Load()方法接收一个String或AssemblyName类型作为参数,这个参数实际上是需要加载的程序集的强名称(程序集名,版本,语言文化,公钥标记)。
它会加载此程序集引用的其他程序集,一般情况下都应该优先使用 这个方法,他的执行效率比LoadFrom要高很多,而且不会造成重复加载的问题(原因在第2点上说明)。
使用这个方法的时候, CLR会应用一定的策略来查找程序集,实际上CLR按如下的顺序来定位程序集:
  ⑴如果程序集有强名称,在首先在全局程序集缓(GAC)中查找程序集。
  ⑵如果程序集的强名称没有正确指定或GAC中找不到,那么通过配置文件中的<codebase>元素指定的URL来查找
  ⑶如果没有指定强名称或是在GAC中找不到,CLR会探测特定的文件夹:
假设你的应用程序目录是C:\AppDir,<probing>元素中的privatePath指定了一个路径Path1,你要定位的程序集是AssemblyName.dll,
则CLR将按照如下顺序定位程序集
  C:\AppDir\AssemblyName.dll
  C:\AppDir\AssemblyName\AssemblyName.dll
  C:\AppDir\Path1\AssemblyName.dll
  C:\AppDir\Path1\AssemblyName\AssemblyName.dll

如果以上方法不能找到程序集,会发生编译错误,如果是动态加载程序集,会在运行时抛出异常!

2:Assembly.LoadFrom()

  这个方法从指定的路径来加载程序集,实际上这个方法被调用的时候,CLR会打开这个文件,通过查找程序集的AssemblyRef元数据表,得知所有引用和需要的程序集,获取其中的程序集版本,语言文化,公钥标记等信息,把他
们传递给 Load方法,接着,Load方法采用上面的策略来查找程序集。
  如果找到了程序集,会和LoadFrom方法中指定的路径做比较,如果路径相同,该程序集会被认为是应用程序的一部分;
  如果路径不同或Load方法没有找到程序集,那该程序集只是被作为一个“数据文件”来加载,不会被认为是应用程序的一部分。
  这就是在第1点中提到的Load方法比LoadFrom方法的执行效率高的原因。
另外,由于可能把程序集作为“数据文件”来加载,所以使用 LoadFrom从不同路径加载相同程序集的时候会导致重复加载。当然这个方法会加载此程序集引用的其他程序集。
Assembly.LoadFrom(@"C:\ABC\Test.dll");

3:Assembly.LoadFile()

  这个方法是从指定的文件来加载程序集,和上面方法的不同之处是这个方法不会加载此程序集引用的其他程序集,需要自己控制并显示加载所有依赖的程序集!

结论:一般大家应该优先选择Load方法来加载程序集,如果遇到需要使用LoadFrom方法的时候,最好改变设计而用Load方法来代替!

LoadFile与LoadFrom的区别

  1、Assembly.LoadFile只载入相应的dll文件,比如Assembly.LoadFile("abc.dll"),则载入abc.dll,假如abc.dll中引用了def.dll的话,def.dll并不会被载入。
Assembly.LoadFrom则不一样,它会载入dll文件及其引用的其他dll,比如上面的例子,def.dll也会被载入。

  2、用Assembly.LoadFrom载入一个Assembly时,会先检查前面是否已经载入过相同名字的Assembly,比如abc.dll有两个版本(版本1在目录1下,版本2放在目录2下),程序一开始时载入了版本1,当使用Assembly.LoadFrom("2\\abc.dll")载入版本2时,不能载入,而是返回版本1。
  Assembly.LoadFile的话则不会做这样的检查,比如上面的例子换成Assembly.LoadFile的话,则能正确载入版本2。
  LoadFile:加载指定路径上的程序集文件的内容。LoadFrom: 根据程序集的文件名加载程序集文件的内容。

区别:

  LoadFile 方法用来来加载和检查具有相同标识但位于不同路径中的程序集.但不会加载程序的依赖项。
  LoadFrom 不能用于加载标识相同但路径不同的程序集。

三、示例

参考文档:

https://www.cnblogs.com/xibei666/p/6243424.html

https://www.cnblogs.com/SavionZhang/p/6531234.html

http://blog.sina.com.cn/s/blog_7e60af8b01015mfu.html (推荐)

https://blog.csdn.net/aaa123524457/article/details/53242877

https://www.cnblogs.com/danielWise/archive/2011/09/07/2170042.html

C#基础之Assembly的更多相关文章

  1. 【Assembly】NO.70.EBook.7.Assembly.1.001-【汇编语言 第3版 张爽】- 基础知识

    1.0.0 Summary Tittle:[Assembly]NO.70.EBook.7.Assembly.1.001-[汇编语言 第3版 张爽]- 基础知识 Style:Assembly Serie ...

  2. 【Assembly】-NO.88.Assembly.2.滴水逆向.1.002-【位运算及基础指令】-

    1.0.0 Summary Tittle:[Assembly]-NO.88.Assembly.2.滴水逆向.1.002-[]- Style:Java Series:Log4j Since:2018-0 ...

  3. 【Unity|C#】基础篇(12)——反射(Reflection)(核心类:Type、Assembly)

    [学习资料] <C#图解教程>(第24章):https://www.cnblogs.com/moonache/p/7687551.html 电子书下载:https://pan.baidu. ...

  4. assembly 基础

    body, table{font-family: 微软雅黑; font-size: 13.5pt} table{border-collapse: collapse; border: solid gra ...

  5. Maven多模块,Dubbo分布式服务框架,SpringMVC,前后端分离项目,基础搭建,搭建过程出现的问题

    现互联网公司后端架构常用到Spring+SpringMVC+MyBatis,通过Maven来构建.通过学习,我已经掌握了基本的搭建过程,写下基础文章为而后的深入学习奠定基础. 首先说一下这篇文章的主要 ...

  6. .NET面试题系列[1] - .NET框架基础知识(1)

    很明显,CLS是CTS的一个子集,而且是最小的子集. - 张子阳 .NET框架基础知识(1) 参考资料: http://www.tracefact.net/CLR-and-Framework/DotN ...

  7. .NET面试题系列[2] - .NET框架基础知识(2)

    3 程序集 面试出现频率:虽然很重要但不怎么出现,可能会考你定义,以及程序集包括什么,然后自然的话题就跑到反射上去了. 重要程度:8/10,很重要 需要理解的程度:知道程序集包括IL和元数据.知道元数 ...

  8. .NET基础拾遗(3)字符串、集合和流

    Index: (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理 (3)字符串.集合与流 (4)委托.事件.反射与特性 (5)多线程开发基础 (6)ADO.NET与数据库开发基础 ...

  9. .NET基础拾遗(4)委托、事件、反射与特性

    Index : (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理基础 (3)字符串.集合与流 (4)委托.事件.反射与特性 (5)多线程开发基础 (6)ADO.NET与数据库开 ...

随机推荐

  1. Ubuntu下解压压缩文件

    1.ZIP解压    ZIP因为它的跨平台使用优点,是目前使用率最高的一种压缩方式,但是它的压缩率相比较tar.gz和tar.gz2来讲,却要低很多.    压缩命令:zip -r archive_n ...

  2. 编写python程序和运行.py文件的方法步骤

    前提:已安装好 Subliume Test 3 且已经添加好python编译系统,已安装好python3.7 一.新建一个文本文档,将后缀名改为.py 二.使用 Subliume Test 3 打开该 ...

  3. 工具(3): 转换Excel表格到MarkDown:exceltk

    源码和下载: 0.1.3 mac: https://github.com/fanfeilong/exceltk/blob/master/pub/exceltk.0.1.3.pkg windows: h ...

  4. zookeeper报错java.net.ConnectException: Connection refused: no further information

    zookeeper报错java.net.ConnectException: Connection refused: no further information 这是在linux 启动 https:/ ...

  5. ViewPager + TabLayout + Fragment + MediaPlayer的使用

    效果图 在gradle里导包  implementation 'com.android.support:design:28.0.0' activity_main <?xml version=&q ...

  6. 源码编译安装php7

    现在新启的项目都是采用php7了,无奈很多Linux发行版中还是php5 第三方php7源在自己本机上用用到无所谓,放到正式环境上还是有点不放心 其实编译安装也就几分钟,麻烦的是各种依赖 先删除老版本 ...

  7. IO多路复用和local概念

    一.local 在多个线程之间使用threading.local对象,可以实现多个线程之间的数据隔离 import time import random from threading import T ...

  8. Spring MVC 使用介绍(四)—— 拦截器

    一.概述 1.接口定义 拦截器由HandlerInterceptor接口定义: public interface HandlerInterceptor { // 预处理方法 boolean preHa ...

  9. 关于sha1加密与md5加密

    1.区别 Hash,一般翻译做"散列",也有直接音译为"哈希"的,就是把任意长度的输入,变换成固定长度的输出,该输出就是散列值.这种转换是一种压缩映射,也就是, ...

  10. POJ1509 Glass Beads 【后缀自动机】

    题目分析: 模板练手.看最长能走多远. 代码: #include<iostream> #include<cstdio> #include<cstdlib> #inc ...