`
lovnet
  • 浏览: 6878414 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
文章分类
社区版块
存档分类
最新评论

谈.NET中几个怪异的CustomAttribute

阅读更多

大家都知道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的语句在这里:

.ver 1:0:0:0

我们再用另外一种方式,仿照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本身却被放到了AssemblyManifest里面,反而和c#编译器的结果不一样了。

事实上,AssemblyVersionAttribute对于CLR本身并没有意义,并不能指定Assembly的版本号。AssemblyVersionAttribute本身只是对于编译器比如c#或者VB.NET等才有意义,编译器根据Attribute的内容生成对应版本号的文件,这个Attribute的内容本身并没有最后进入结果的Assembly

除此之外,还有一些Attribute本身并不是CustomAttribute,而是作为Metadata中的特殊信息存在,可以是Bit Flag,也可以是Signature的一部分。典型的例子是和COM Interop有关的Attribute,如MarshalAsAttributeDllImportAttributeStructLayoutAttribute,比如:

[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名字和EntryPointlasterr则是SetLastError=truemarshal(bool)对应MarshalAs(bool)preservesig对应PreserveSig=true。其中,有些信息是整个函数的Signature的一部分,有些则是BitFlagCLR在运行的时候动态解析这些信息速度会更快,比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 0016位长的标识,总是不变,03是字符串长度,后面的32 2E 32是字符串的UTF8编码,也就是2.2(这里只讲到字符串,对于其他不同类型的参数解释方式又不一样),00 0016位长的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实现方法调用拦截(就是aop)

    在.NET框架中,Attribute是一种元数据,用于向编译器、IDE、运行时环境等提供额外的信息。这些信息可以用来修饰类、接口、方法、属性等各种编程元素,从而实现特定的功能或扩展。AOP(面向切面编程)是一种编程范式...

    Pro .NET 2.0 Windows Forms And Custom Controls In VB 2005_part1of5

    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_part3of5

    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_part4of5

    Pro .NET 2.0 Windows Forms And Custom Controls In VB 2005.pdf 精通VB2005编程DotNet2.0窗口表单和用户控制界面

    Asp.Net几个实用案例

    Asp.Net几个实用案例 Asp.Net几个实用案例 Asp.Net几个实用案例 Asp.Net几个实用案例

    Attribute在NET中的应用

    在.NET框架中,属性(Attribute)是一种元数据,可以附加到程序元素,如类、方法、属性等,为编译器、运行时环境或其他工具提供额外的信息。它们是编程中的一个重要概念,允许开发者向代码中添加非执行性的描述性...

    Ext.NET中文API

    Ext.NET中文API ext.net中文API接口说明,主要介绍ext.net下各个类的基本属性和方法及其简单用法

    S7.NET中文说明书.pdf

    综上所述,S7.NET是一个功能强大的PLC驱动程序,不仅支持广泛的西门子PLC型号,而且通过其简洁易用的API接口,大大简化了与PLC设备的交互过程。无论是对于初学者还是有经验的开发人员来说,S7.NET都是一款值得推荐的...

    Attribute在.net编程中的应用(全).doc

    下面通过几个.NET中常见的Attribute来了解其具体用途: ##### 1. Conditional Attribute - **功能**:用于条件编译,当满足特定条件时,编译器才会编译该Attribute标记的代码。通常在调试时使用。 - **示例**: `...

    .net反射与特性的使用方法

    在上面的例子中,我们定义了一个名为`CustomAttribute`的自定义特性,并将其应用于`MyMethod`。这样,我们就可以在运行时通过反射获取这个特性及其附加信息: ```csharp MethodInfo myMethod = myType.GetMethod(...

    Attribute在.NET中的应用

    总的来说,Attribute是.NET开发中的一个重要工具,它增强了代码的表达能力和灵活性,同时也方便了工具和库的开发者获取和理解代码的意图。对于初级.NET开发者来说,理解并熟练使用Attribute是提高编程效率和代码质量...

    .NET6.0官方中文文档.pdf

    在.NET 6.0的概述中,我们了解到.NET的架构组件,包括.NET类库、.NET Standard,以及它们之间的关系。.NET Standard是一个规范,定义了一组可跨.NET实现共享的API,使得开发者可以在不同的.NET平台上编写可移植代码...

    ado.net中文手册

    ado.net中文手册ado.net中文手册

    Pro .NET 2.0 Windows Forms And Custom Controls In VB 2005_part5of5

    Pro .NET 2.0 Windows Forms And Custom Controls In VB 2005.pdf 精通VB2005编程DotNet2.0窗口表单和用户控制界面

    .NET中文分词示例代码

    在.NET开发环境中,中文分词是一项重要的任务,特别是在文本处理、搜索引擎、自然语言处理等领域。本文将详细探讨.NET中文分词示例代码及其使用的盘古分词类库,旨在帮助开发者理解和实现中文分词功能。 首先,让...

    VB.Net自己写的一个控件:ComboBox下拉列表中显示多列数据

    VB.Net开发一个小程序时候,用到一个显示多列的ComboBox,而且从数据库中取出来的数据表要绑定到一个ComboBox中。找来找去,找不到。上Baidu Google很多人说:在VB.Net中的ComboBox只能绑定一列数据。以前的VBA和VB的...

    Gmap.net中文,并集成了高德地图(MAPAbc)

    Gmap.net是一个开源的JavaScript地图API,它允许开发者在网站上嵌入交互式地图,提供包括地理位置搜索、标记显示、路线规划等功能。它的原始版本主要依赖于Google Maps API,但随着中国市场的重视,Gmap.net逐渐本地...

    asp.net Mvc项目中使用FastReport.NET

    asp.net Mvc项目中使用FastReport.NET的说明

    DWZ框架在ASP.Net中的运用

    在ASP.NET中使用DWZ框架时,开发者需要注意以下几点: 1. **集成DWZ**:首先需要将DWZ框架的JavaScript和CSS文件引入到ASP.NET项目中,这通常通过在页面头部引用相关资源来完成。 2. **数据交互**:DWZ框架支持JSON...

    vb.net实现tcp通讯

    在.NET框架中,VB.NET(Visual Basic .NET)是一种强大的编程语言,用于构建各种类型的应用程序,包括网络通信。TCP(Transmission Control Protocol)是互联网协议栈中的基础协议,用于提供可靠的、面向连接的数据...

Global site tag (gtag.js) - Google Analytics