【问】

假设有一个类库文件LibraryA,其中有一个ClassA,该类的AssemblyName为“LibraryA”(编译后的文件是LibraryA.dll)。另外有一个LibraryB.dll类库文件,其中AssemblyName和其命名空间一样,并且其引用LibraryA.dll。它们代码如下:

[C#]

【LibraryA.dll】

namespace A{    public class ClassA    {        public ClassA()        {            Console.WriteLine("成功执行ClassA的构造函数。");        }                   }}

【LibraryB.dll】

using LibraryA;

namespace LibraryB{    public class ClassB    {        public ClassA GetClassA()        {            return new ClassA();        }

        public ClassB()        {            Console.WriteLine("成功执行ClassB的构造函数。");        }    }}

[VB.NET]

【LibraryA.dll】

Namespace A       Public Class ClassA                 Public Sub New()                           Console.WriteLine("成功执行ClassA的构造函数。")                 End Sub      End ClassEnd Namespace

【LibraryB.dll】

Imports LibraryA

Namespace LibraryB         Public Class ClassB                 Public Function GetClassA() As ClassA                          Return New ClassA()                 End Function

                 Public Sub New()                          Console.WriteLine("成功执行ClassB的构造函数。")                 End Sub         End ClassEnd Namespace

现在假设有一个控制台程序(包含Main主函数,该控制台类也已经引用了LibraryA)。要求:

1、设法使用反射方法运行LibraryA的构造函数。

2、设法使用动态加载方法(只允许加载LibraryB.dll,假设位于D:\目录下),运行GetClassA方法。

假设在D:\ 下有两个文件夹(f1和f2)。在f1中复制原本LibraryB.dll一份;然后在f2复制修改过的LibraryB.dll(就是构造函数输出变更为“成功执行ClassB的构造函数更新版”,然后重新编译拷贝进入f2)。我在控制台主程序中动态加载两个不同路径,但是相同版本的LibraryB.dll。请问以下程序运行之后结果是什么?

[C#]

Assembly asm = Assembly.LoadFrom(@“D:\f1\LibraryB.dll”);asm.CreateInstance(“LibraryB.ClassB”);asm = Assembly.LoadFrom (@“D:\f2\LibraryB.dll”);asm.CreateInstance(“LibraryB.ClassB”);

[VB.NET]

Dim asm As Assembly = Assembly.LoadFrom (@“D:\f1\LibraryB.dll”)asm.CreateInstance(“LibraryB.ClassB”)asm = Assembly. LoadFrom (@“D:\f2\LibraryB.dll”)asm.CreateInstance(“LibraryB.ClassB”)

【错误回答】

1)

[C#]

Assembly asm = Assembly.Load(“A”);asm.CreateInstance(“A.ClassA”);

[VB.NET]

Dim asm As Assembly = Assembly.Load(“A”)asm.CreateInstance(“A.ClassA”)

理由:Load需要一个AssemblyName,也就是Namespace的名称。然后后面的CreateInstance需要一个“命名空间名.类名”。

2)

[C#]

Assembly asm = Assembly.LoadFile(@“D:\LibraryB.dll”);asm.CreateInstance(“LibraryB.ClassB”).GetType().GetMethod(“GetClassA”);

[VB.NET]

Dim asm As Assembly = Assembly.LoadFile(“D:\LibraryB.dll”)asm.CreateInstance(“LibraryB.ClassB”).GetType().GetMethod(“GetClassA”)

3)输出两行话——

成功执行ClassB的构造函数。

成功执行ClassB的构造函数更新版。

【正解】

第一问:初学者似乎没有区分“AssemblyName”、“Namespace”的区别——的确,很少有教师去教他们区别这两者之间的差异。AssemblyName是“程序集”名字,是用于记录程序信息的一种特殊唯一标识符,供.NET的底层CLR调用识别的;Namespace是面向程序设计者,使得客户可以将不同的类进行归档,因此Namespace类似文件夹,而每一个Class类似于文件夹中的文件;至于Assembly相当于“硬盘的卷标”作用。

因此,Assembly.Load的第一个参数需要的是AssemblyName,和Namespace并无直接联系。你完全可以根据需要修改AssemblyName(方法:右键项目,选择“属性”,在“程序(Application)”面板上就可以看到)。

第二问和第三问其实是考察如何正确使用LoadFile和LoadFrom动态加载指定的类库。

第二问:错误代码将导致一个“无法找到加载文件”的类似错误,其原因是在于LibraryB.dll引用了LibraryA.dll,但是如果使用了LoadFile,则动态反射LibraryB.dll的时候不会自动加载程序集LibraryA.dll,但是“GetClassA”方法却需要使用到LibraryA中的类。继而引发错误。而要使得被引用的其它dll也一并加载进来,应该使用LoadFrom方法。

第三问和第二问相反,考察LoadFile和LoadFrom加载一个程序集相同,但是处于不同位置的类库(注意:这里“程序集相同”是指在源代码基础上略作修改,形成副本的dll)。

第三问:LoadFile只管加载类库,只要指定了绝对或者相对屋里路径的类库,其总是加载并以此为准;但是LoadFrom不同——如果遇到了相同的程序集的类库文件,以第一次的加载为准。所以输出的两句话都是“成功执行ClassB的构造函数。”。

【总结】

1 AssemblyNameNamespace不是一回事情,AssemblyName是供.NET使用的;而Namespace是客户自定义的“归档”类的命名空间。Assembly.Load需要前者,但是刚创建项目时,VS默认情况下两者一致。

2LoadFile只管加载程序集文件,但是反射仅限于当前程序集自身中的方法、属性等,如果需要反射引用到的外部程序集,必须使用LoadFrom

3LoadFrom对于相同程序集文件只加载第一次,因此只返回第一次的结果;要反射不同路径但是相同的程序集文件,必须使用LoadFile

【拓展】

“程序集”是包含一个或者多个类型定义文件和资源文件的集合,一般地当创建了一个完整的.NET程序(无论是C#或者是VB.NET的),VS默认就为其产生一个程序集。程序集一般包含程序的若干信息(比如程序的版本号等),它们都是存储在一个叫做“Assembly.cs”(VB.NET中是AssemblyInfo.vb)的文件中。如果双击打开该文件,我们便可窥知一二(注释删除)——

[C#]

[assembly: AssemblyTitle("CSharp")][assembly: AssemblyDescription("")][assembly: AssemblyConfiguration("")][assembly: AssemblyCompany("Microsoft IT")][assembly: AssemblyProduct("CSharp")][assembly: AssemblyCopyright("Copyright © Microsoft IT 2011")][assembly: AssemblyTrademark("")][assembly: AssemblyCulture("")][assembly: AssemblyVersion("1.0.0.0")][assembly: AssemblyFileVersion("1.0.0.0")]

[VB.NET]

<Assembly: AssemblyTitle("CSharp")><Assembly: AssemblyDescription("")><Assembly: AssemblyConfiguration("")><Assembly: AssemblyCompany("Microsoft IT")><Assembly: AssemblyProduct("CSharp")><Assembly: AssemblyCopyright("Copyright © Microsoft IT 2011")><Assembly: AssemblyTrademark("")><Assembly: AssemblyCulture("")><Assembly: AssemblyVersion("1.0.0.0")><Assembly: AssemblyFileVersion("1.0.0.0")>

下面来说说如何读取这些数据:

1)AssemblyVersion是程序的版本号。一般地,通过读取程序的版本号可以了解程序是否处于最新状态,不少更新程序往往就通过类似手段或者方式更新程序的。要读取一个当前程序的版本号,我们通过Assembly.GetName方法获取Version属性即可。

[C#]

AssemblyName an = Assembly.GetExecutingAssembly().GetName();Console.WriteLine(an.Version);

[VB.NET]

Dim an As AssemblyName = Assembly.GetExecutingAssembly().GetName()Console.WriteLine(an.Version)

GetExecutingAssembly是一个获取当前正运行的程序的Assembly实体。如果要读取指定某个程序的版本号,我们可以使用Assembly.LoadFile或者Assembly.LoadFrom加载一个dll或者是exe文件,然后通过GetName获取AssemblyName,再按照上面相同的方法通过诸如Version一类的属性就可以了。

顺便说一下“AssemblyName”。通过“拓展”之前的分析就可以其是一个“程序集”名称。实际上.NET把它定义成一个类,专门可以用于获取Culture(对应AssemblyCulture),Name(就是指当前程序的“程序集名称”)和Version(指代AssemblyVersion)等信息其中Version还包括“Major”(主版本号)、“Minor”(次版本号)、“Build”(编译版本号)和“Revision”(修正版本号)。它们作用分别是:

1)  Major(主板本号)+Minor(次版本号):两个合成用于对外发布,对外告知客户目前程序的版本。一般地,Major表示“里程碑”式的程序更新(比如Windows98XP,那么Major就会产生影响,自增1);而Minor是在当前程序中进行的局部重大更新(比如在原来程序基础上增删了功能,或者发现了漏洞进行修补等)时用到。

2)  Build(编译版本号):内部告知开发人员或者测试人员,目前该程序从开始编译到全部完成,总共编译的次数(每重新编译一次此自增1)。

3)  Revision(修正版本号):每当有一个Bug在内测时被发现,此版本号在原来基础上加1,表示总共从开始到完成历经多少了Bug修复。

AssemblyVersion和AssemblyFileVersion一般需要保持一致。前者是被.NET内部反射使用到的,后者是对外,可以通过右键=>属性中查看得到。比如查看Word2010程序我们可以了解以下信息:

第一个“14”表示Word家族已经历经到目前开发了14个不同的“里程碑”式版本,第二个“0”表示目前为止尚未发现在office2010中有明显增加或是删除功能;“5123”表示该版本的Word程序总共编译了5123次,而“5000”表示从开始到结束总共修正了5000个Bug。

除了可以在Assembly.cs中看到文件信息,我们同样可以通过右键某个csproj(VB.NET中是vbproj),“属性”=>“应用程序(Application)”中得到相同的信息:

默认主版本号是1,其余都是0;下方的一个“复选框”是“自动为Revision版本号自增1”;也就是说,每次对外发布时,该程序的Revision会在原来基础上加上1。

2)除了版本号之外,其余的Assembly信息(比如AssemblyTitle)可以通过这样的方式获得:

[C#]

AssemblyTitleAttribute at = (AssemblyTitleAttribute) AssemblyTitle.GetCultureAttribute(Assembly.GetExecutingAssembly(),typeof(AssemblyTitle));Console.WriteLine(at.Title);

[VB.NET]

   Dim at As AssemblyTitleAttribute = DirectCast(AssemblyTitleAttribute.GetCustomAttribute(Assembly.GetExecutingAssembly(), GetType(AssemblyTitleAttribute)), AssemblyTitleAttribute)  Console.WriteLine(at.Title)

更一般地,因为Assembly文件中这些都是“特性”类(省略了后缀Attribute)。因此我们可以使用反射的方法获取它们,伪代码描述如下:

[C#]

XXXAttribute 变量名= XXXAttribute.GetCustomAttribute(Assembly实体对象,typeof(XXXAttribute));

变量名.属性;

[VB.NET]

Dim 变量名 As XXXAttribute== XXXAttribute.GetCustomAttribute(Assembly实体对象,typeof(XXXAttribute))

变量名.属性

几点说明:

1)  XXX”表示对应Assembly文件中的“assembly:”后面的那个部分。

2)  AttributeCultureAttributeVersion不能使用以上方法获取,只能使用AttributeName方法。因为它们是编译器生成的,不是直接输出供外部客户通过“右键”=>“属性”的方式直接可以看到的。

转载于:https://www.cnblogs.com/ServiceboyNew/archive/2011/11/17/2241215.html

动态反射——Load,LoadFrom和LoadFile相关推荐

  1. Assembly中Load, LoadFrom, LoadFile以及AppDomain, Activator类中相应函数的区别

    Assembly和AppDomain的一些关于动态加载程序集的函数有些令人头疼,但细细研究后还是可以将他们区分的. 这些函数大致可以分为四类: 第一类:加载到Load Context内 Load Co ...

  2. ulua 动态反射在IOS上的问题

    2019独角兽企业重金招聘Python工程师标准>>> ulua同时支持静态代码生成和动态接口反射. 以前在cocos2d中,c++ 没有反射能力,自然需要将所有的接口都静态生成代码 ...

  3. C#反射之Assembly.Load,Assembly.LoadFile 与 Assembly.LoadFrom方法介绍

    一些关于C#反射的知识,估计也就最多达到使用API的程度,至于要深入了解,以现在的水平估计很难做到,所以下面此篇文章,以作为一个阶段的总结. 对于反射的总结,我想从以下几个方面展开,首先是反射程序集, ...

  4. 反射load,loadfile,LoadFrom区别

    反射加载数据用法 Load Assembly assembly = Assembly.Load("Ruanmou.DB.MySql");//dll名称无后缀 从当前目录加载dll ...

  5. Assembly.Load,Assembly.LoadFile 与 Assembly.LoadFrom

    Load为最佳方案,用完全限定名进行加载程序集.完全限定名为:程序集名称,version, Culture, PublicKeyToken LoadFile 方法用来来加载和检查具有相同标识但位于不同 ...

  6. 关于反射的一些总结(转)

    关于反射的一些总结: 1) Load,LoadFrom和LoadFile: Load:只加载本地程序集中指定的类(通过命名空间等方式指定). LoadFrom:通过外部相对或者绝对路径加载指定的类库或 ...

  7. DirectX11进阶6_静态天空盒、反射动态场景与天空盒、Render-To-Texture(Fade/MiniMap/ScreenShot)

    一.静态天空盒与反射天空盒 这一章我们主要学习由6个纹理所构成的立方体映射,以及用它来实现一个静态天空盒. 但是在此之前先要消除两个误区: 认为这一章的天空盒就是简单的在一个超大立方体的六个面内部贴上 ...

  8. C#反射与特性(一):反射基础

    1. 说明 1.1 关于反射.特性 在 <C# 7.0 本质论>中,关于这方面的知识在 <第十八章 反射.特性和动态编程>:在<C# 7.0 核心技术指南>中,这部 ...

  9. [转] 接触C# 反射 2

    逆心 原文 反射基础,2013-4. 反射用于在程序运行过程中,获取类里面的信息或发现程序集并运行的一个过程.通过反射可以获得.dll和.exe后缀的程序集里面的信息.使用反射可以看到一个程序集内部的 ...

最新文章

  1. linux mysql设置开机启动脚本_linux下添加oracle自启动脚本
  2. 算法艺术——网络最大流
  3. MySQL缓存之Qcache与buffer pool对比
  4. 前端学习(2598):按钮控制操作
  5. Point和PointF
  6. 一个显示器分两个屏幕_桌面改造计划2.0:一个显示器不够那就两个,桌面好物分享...
  7. 【英语学习】【Daily English】U12 E-World L03 Black Friday is coming!
  8. 中国水雾化铁粉行业市场供需与战略研究报告
  9. python pip更改源
  10. 【论文写作】精品课程教学网站中用户管理如何写
  11. alpha-beta 极大极小值剪枝算法
  12. 模拟信号的采样定理MATLAB实现
  13. 关于Odoo盘盈成本和计价法的讨论
  14. win电脑C/D盘清理技巧
  15. java中Date计算时间差
  16. 10+年程序员总结的20+条经验教训
  17. Upload-labs 1-21关 靶场通关攻略(全网最全最完整)
  18. socket中的read()
  19. 从保障淘宝到全球市场“第一阵营”,阿里云的DDoS防护之路走了多远?
  20. IEEE顶级期刊和会议-车辆动力学及其控制和计算机视觉CV

热门文章

  1. 仿生蛇类机器人 特点_今日项目:功能表面仿生激光强化及其修复再造技术
  2. python强类型_python动态性强类型用法实例
  3. 『设计模式』职责链模式(Chain of Responsibility) 可怜的加薪、请假之路
  4. 『数据库』数据库编程(概念性的东西,应用一般,甚至有点过时,用来考试)
  5. springboot 之 webscoket 服务端推送
  6. Solr+Hbase多条件查(优劣互补)
  7. 【IT笔试面试题整理】给定二叉树,给每层生成一个链表
  8. ADAS视觉方案盘点下篇:11家创业公司完全解读
  9. Eigen入门之密集矩阵 5 - 再谈Matrix初始化
  10. 转正老板让你谈谈你的看法_让我们谈谈逻辑回归