大家都知道AssemblyVersionAttribute是用来指定Assembly的版本号使用的,但是不知道你有没有考虑过这个问题:这个Attribute真的生成到了最后的Assembly中吗?
我们建立一个简单的C#项目试一下便可以知道。在新建的C#项目中AssemblyInfo.cs缺省有如下的内容:
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("TestAssemblyVersionAttribute")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("MSIT")]
[assembly: AssemblyProduct("TestAssemblyVersionAttribute")]
[assembly: AssemblyCopyright("Copyright © MSIT 2008")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("a39eea23-7bc8-47c2-aca8-93136279a0ec")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
|
Build一下,生成的文件用ILDASM查看,大部分Attribute都可以在Manifest中找到:
// Metadata version: v2.0.50727
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 2:0:0:0
}
.assembly TestAssemblyVersionAttribute
{
.custom instance void [mscorlib]System.Reflection.AssemblyTitleAttribute::.ctor(string) = ( 01 00 1C 54 65 73 74 41 73 73 65 6D 62 6C 79 56 // ...TestAssemblyV
65 72 73 69 6F 6E 41 74 74 72 69 62 75 74 65 00 // ersionAttribute.
00 )
.custom instance void [mscorlib]System.Reflection.AssemblyDescriptionAttribute::.ctor(string) = ( 01 00 00 00 00 )
.custom instance void [mscorlib]System.Reflection.AssemblyConfigurationAttribute::.ctor(string) = ( 01 00 00 00 00 )
.custom instance void [mscorlib]System.Reflection.AssemblyCompanyAttribute::.ctor(string) = ( 01 00 04 4D 53 49 54 00 00 ) // ...MSIT..
.custom instance void [mscorlib]System.Reflection.AssemblyProductAttribute::.ctor(string) = ( 01 00 1C 54 65 73 74 41 73 73 65 6D 62 6C 79 56 // ...TestAssemblyV
65 72 73 69 6F 6E 41 74 74 72 69 62 75 74 65 00 // ersionAttribute.
00 )
.custom instance void [mscorlib]System.Reflection.AssemblyCopyrightAttribute::.ctor(string) = ( 01 00 16 43 6F 70 79 72 69 67 68 74 20 C2 A9 20 // ...Copyright ..
4D 53 49 54 20 32 30 30 38 00 00 ) // MSIT 2008..
.custom instance void [mscorlib]System.Reflection.AssemblyTrademarkAttribute::.ctor(string) = ( 01 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.InteropServices.ComVisibleAttribute::.ctor(bool) = ( 01 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.InteropServices.GuidAttribute::.ctor(string) = ( 01 00 24 61 33 39 65 65 61 32 33 2D 37 62 63 38 // ..$a39eea23-7bc8
2D 34 37 63 32 2D 61 63 61 38 2D 39 33 31 33 36 // -47c2-aca8-93136
32 37 39 61 30 65 63 00 00 ) // 279a0ec..
.custom instance void [mscorlib]System.Reflection.AssemblyFileVersionAttribute::.ctor(string) = ( 01 00 07 31 2E 30 2E 30 2E 30 00 00 ) // ...1.0.0.0..
// --- The following custom attribute is added automatically, do not uncomment -------
// .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows.
.hash algorithm 0x00008004
.ver 1:0:0:0
}
.module TestAssemblyVersionAttribute.exe
// MVID: {383D6DF2-7A1D-41BA-944D-26979117014E}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x00350000
|
只有一个例外,也就是AssemblyVersionAttribute在这个Manifest中是找不到的。而真正的指定Version的语句在这里:
我们再用另外一种方式,仿照C#编译器来动态生成一个Assembly来试一下:
AssemblyName name = new AssemblyName();
name.Name = "Result";
name.Version = new Version("1.1");
AssemblyBuilder asmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.ReflectionOnly);
ConstructorInfo asmVersionCtor = typeof(AssemblyVersionAttribute).GetConstructor(new Type[] { typeof(string) });
CustomAttributeBuilder attrBuilder = new CustomAttributeBuilder(asmVersionCtor, new object[] { "2.2" });
asmBuilder.SetCustomAttribute(attrBuilder);
asmBuilder.Save("Result.DLL");
|
这里我们指定Assembly版本号为1.1,而AssemblyVersionAttribute则是2.2,那么最终的结果如何呢?
// Metadata version: v2.0.50727
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 2:0:0:0
}
.assembly Result
{
.custom instance void [mscorlib]System.Reflection.AssemblyVersionAttribute::.ctor(string) = ( 01 00 03 32 2E 32 00 00 ) // ...2.2..
.hash algorithm 0x00008004
.ver 1:1:0:0
}
.module RefEmit_OnDiskManifestModule
// MVID: {AF35088A-F419-4F88-A011-D29FF41C1E20}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x00880000
|
可以看到,首先AssemblyVersionAttribute并没有决定Assembly的版本号,而AssemblyVersionAttribute本身却被放到了Assembly的Manifest里面,反而和c#编译器的结果不一样了。
事实上,AssemblyVersionAttribute对于CLR本身并没有意义,并不能指定Assembly的版本号。AssemblyVersionAttribute本身只是对于编译器比如c#或者VB.NET等才有意义,编译器根据Attribute的内容生成对应版本号的文件,这个Attribute的内容本身并没有最后进入结果的Assembly。
除此之外,还有一些Attribute本身并不是CustomAttribute,而是作为Metadata中的特殊信息存在,可以是Bit Flag,也可以是Signature的一部分。典型的例子是和COM Interop有关的Attribute,如MarshalAsAttribute,DllImportAttribute,StructLayoutAttribute,比如:
[DllImport("kernel32.dll", EntryPoint="Beep", PreserveSig=true, SetLastError=true)]
[return:MarshalAs(UnmanagedType.Bool)]
public static extern bool MyBeep(uint freq, uint duration);
|
实际上对应的则是:
.method public hidebysig static pinvokeimpl("kernel32.dll" as "Beep" lasterr winapi)
bool marshal( bool) MyBeep(uint32 freq,
uint32 duration) cil managed preservesig
{
}
|
其中pinvokeimpl对应DllImportAttribute,”kernel32.dll” as “Beep”很明显对应DLL名字和EntryPoint,lasterr则是SetLastError=true,marshal(bool)对应MarshalAs(bool),preservesig对应PreserveSig=true。其中,有些信息是整个函数的Signature的一部分,有些则是BitFlag,CLR在运行的时候动态解析这些信息速度会更快,比CustomAttribute要快很多,原因很简单:我们随便找一个CustomAttribute来看:
.assembly Result
{
.custom instance void [mscorlib]System.Reflection.AssemblyVersionAttribute::.ctor(string) = ( 01 00 03 32 2E 32 00 00 ) // ...2.2..
.hash algorithm 0x00008004
.ver 1:1:0:0
}
|
看看上面的AssemblyVersionAttribute,内容为2.2,这个2.2是怎么读出来的呢?.ctor(string)表示构造Attribute的实例的时候要调用参数是String的构造函数,而后面的那一串数字,则是根据CLI所定义的规则指定的构造函数的参数:第一个01 00是16位长的标识,总是不变,03是字符串长度,后面的32 2E 32是字符串的UTF8编码,也就是2.2(这里只讲到字符串,对于其他不同类型的参数解释方式又不一样),00 00是16位长的0,表示后面跟0个可选命名参数(比如上面提到的PreserveSig=true这样的形式)。换句话说,CustomAttribute是需要CLR在运行时候动态调用构造函数,并分析这一串二进制数值得出参数来创建一个新的CustomAttribute的实例,比动态解析Metadata要慢。当然了,只有CLR自己支持的特殊Attribute才有这种待遇了,一般我们写的Attribute还是要老老实实的这么构造的。这些特殊的Attribute,用GetCustomAttributes函数是无法得到的,而只能用特殊方法获得。比如PreserveSig只能用GetMethodImplementationFlags函数获得。
Adam Nathan有一篇文章也讲到了这个问题,并有一个比较详尽的列表,有兴趣的朋友也可以参考一下他的这篇文章:http://blogs.msdn.com/adam_nathan/archive/2003/04/29/56645.aspx
作者: 张羿(ATField)
Blog: http://blog.csdn.net/atfield
http://blogs.msdn.com/yizhang
转载请注明出处
分享到:
相关推荐
在.NET框架中,Attribute是一种元数据,用于向编译器、IDE、运行时环境等提供额外的信息。这些信息可以用来修饰类、接口、方法、属性等各种编程元素,从而实现特定的功能或扩展。AOP(面向切面编程)是一种编程范式...
Pro .NET 2.0 Windows Forms And Custom Controls In VB 2005.pdf 精通VB2005编程DotNet2.0窗口表单和用户控制界面
Pro .NET 2.0 Windows Forms And Custom Controls In VB 2005.pdf 精通VB2005编程DotNet2.0窗口表单和用户控制界面
Pro .NET 2.0 Windows Forms And Custom Controls In VB 2005.pdf 精通VB2005编程DotNet2.0窗口表单和用户控制界面
Asp.Net几个实用案例 Asp.Net几个实用案例 Asp.Net几个实用案例 Asp.Net几个实用案例
在.NET框架中,属性(Attribute)是一种元数据,可以附加到程序元素,如类、方法、属性等,为编译器、运行时环境或其他工具提供额外的信息。它们是编程中的一个重要概念,允许开发者向代码中添加非执行性的描述性...
Ext.NET中文API ext.net中文API接口说明,主要介绍ext.net下各个类的基本属性和方法及其简单用法
综上所述,S7.NET是一个功能强大的PLC驱动程序,不仅支持广泛的西门子PLC型号,而且通过其简洁易用的API接口,大大简化了与PLC设备的交互过程。无论是对于初学者还是有经验的开发人员来说,S7.NET都是一款值得推荐的...
下面通过几个.NET中常见的Attribute来了解其具体用途: ##### 1. Conditional Attribute - **功能**:用于条件编译,当满足特定条件时,编译器才会编译该Attribute标记的代码。通常在调试时使用。 - **示例**: `...
在上面的例子中,我们定义了一个名为`CustomAttribute`的自定义特性,并将其应用于`MyMethod`。这样,我们就可以在运行时通过反射获取这个特性及其附加信息: ```csharp MethodInfo myMethod = myType.GetMethod(...
总的来说,Attribute是.NET开发中的一个重要工具,它增强了代码的表达能力和灵活性,同时也方便了工具和库的开发者获取和理解代码的意图。对于初级.NET开发者来说,理解并熟练使用Attribute是提高编程效率和代码质量...
在.NET 6.0的概述中,我们了解到.NET的架构组件,包括.NET类库、.NET Standard,以及它们之间的关系。.NET Standard是一个规范,定义了一组可跨.NET实现共享的API,使得开发者可以在不同的.NET平台上编写可移植代码...
ado.net中文手册ado.net中文手册
Pro .NET 2.0 Windows Forms And Custom Controls In VB 2005.pdf 精通VB2005编程DotNet2.0窗口表单和用户控制界面
在.NET开发环境中,中文分词是一项重要的任务,特别是在文本处理、搜索引擎、自然语言处理等领域。本文将详细探讨.NET中文分词示例代码及其使用的盘古分词类库,旨在帮助开发者理解和实现中文分词功能。 首先,让...
VB.Net开发一个小程序时候,用到一个显示多列的ComboBox,而且从数据库中取出来的数据表要绑定到一个ComboBox中。找来找去,找不到。上Baidu Google很多人说:在VB.Net中的ComboBox只能绑定一列数据。以前的VBA和VB的...
Gmap.net是一个开源的JavaScript地图API,它允许开发者在网站上嵌入交互式地图,提供包括地理位置搜索、标记显示、路线规划等功能。它的原始版本主要依赖于Google Maps API,但随着中国市场的重视,Gmap.net逐渐本地...
asp.net Mvc项目中使用FastReport.NET的说明
在ASP.NET中使用DWZ框架时,开发者需要注意以下几点: 1. **集成DWZ**:首先需要将DWZ框架的JavaScript和CSS文件引入到ASP.NET项目中,这通常通过在页面头部引用相关资源来完成。 2. **数据交互**:DWZ框架支持JSON...
在.NET框架中,VB.NET(Visual Basic .NET)是一种强大的编程语言,用于构建各种类型的应用程序,包括网络通信。TCP(Transmission Control Protocol)是互联网协议栈中的基础协议,用于提供可靠的、面向连接的数据...