Attribute鲜为人知的两个特性记录

    Attribute作为一种标记在我们的.net中随处可见,比如DatContract,DatMember,Serializable等等,各种用途的标记。是的我们的代码更加简洁,对于Attribute用好了,可以很好的简化我们的开发,比如PostSharp的AOP实现就是一种基于Attribute的标记编译时注入。在随笔中有关于IOC,AOP利用Attribute标记简化开发的实例。

   在使用Attribute时候发现了些鲜为人知的特性:

1:利用GetCustomAttributes传入的Attribute返回得到包括派生类。

2:GetCustomAttributes每次返回的对象都是经过发射出来的没有缓存。

   1:GetCustomAttributes传入的Attribute返回得到包括派生类:

       这里将采用一个测试类来验证:

[AttributeUsage(AttributeTargets.Class)] 
  public class TestImplementsAttribute : Attribute 
  { 
      public string Name 
      { get; set; } 
  }

 

private static void TestMutilpeImplements() 

    var type = typeof(Program); 
    var attrs = type.GetCustomAttributes(typeof(TestImplementsAttribute), false); 
    Console.WriteLine(string.Format("TestImplementsAttribute:({0})",attrs.Length)); 
    foreach (var item in attrs) 
    { 
        Console.WriteLine("  " + item.GetType().FullName); 
    } 
    attrs = type.GetCustomAttributes(typeof(SerializableAttribute), false); 
    Console.WriteLine(string.Format("SerializableAttribute:({0})", attrs.Length)); 
    foreach (var item in attrs) 
    { 
        Console.WriteLine("  " + item.GetType().FullName); 
    } 

    attrs = type.GetCustomAttributes(typeof(Attribute), false); 
    Console.WriteLine(string.Format("(base type)Attribute:({0})", attrs.Length)); 
    foreach (var item in attrs) 
    { 
        Console.WriteLine("  " + item.GetType().FullName); 
    } 

}

输出为: 

这里我们可以很清晰的看见当传入Attribute类型时候返回包含了SerializableAttribute和TestImplementsAttribute两个。

2:GetCustomAttributes每次返回的对象都是经过发射出来的没有缓存:

测试代码可以看出来,不是同一个地址引用:

private static void TestAttributeActiver() 
      { 
          var type = typeof(Program); 
          var attr1 = type.GetCustomAttributes(typeof(TestImplementsAttribute), false)[0]; 
          var attr2 = type.GetCustomAttributes(typeof(TestImplementsAttribute), false)[0]; 
          Console.WriteLine(Object.ReferenceEquals(attr1, attr2));            
      } 

输出值为false。 

我们在看看

.下面是 reflector的反编译结果(Attribute.GetCustomAttributes):

internal static unsafe object[] GetCustomAttributes(Module decoratedModule, int decoratedMetadataToken, int pcaCount, RuntimeType attributeFilterType, bool mustBeInheritable, IList derivedAttributes)
{
    if (decoratedModule.Assembly.ReflectionOnly)
    {
        throw new InvalidOperationException(Environment.GetResourceString("Arg_ReflectionOnlyCA"));
    }
    MetadataImport metadataImport = decoratedModule.MetadataImport;
    CustomAttributeRecord[] customAttributeRecords = CustomAttributeData.GetCustomAttributeRecords(decoratedModule, decoratedMetadataToken);
    Type elementType = (((attributeFilterType == null) || attributeFilterType.IsValueType) || attributeFilterType.ContainsGenericParameters) ? typeof(object) : attributeFilterType;
    if ((attributeFilterType == null) && (customAttributeRecords.Length == 0))
    {
        return (Array.CreateInstance(elementType, 0) as object[]);
    }
    object[] attributes = Array.CreateInstance(elementType, customAttributeRecords.Length) as object[];
    int length = 0;
    SecurityContextFrame frame = new SecurityContextFrame();
    frame.Push(decoratedModule.Assembly.InternalAssembly);
    Assembly lastAptcaOkAssembly = null;
    for (int i = 0; i < customAttributeRecords.Length; i++)
    {
        bool flag2;
        bool flag3;
        object obj2 = null;
        CustomAttributeRecord caRecord = customAttributeRecords[i];
        RuntimeMethodHandle ctor = new RuntimeMethodHandle();
        RuntimeType attributeType = null;
        int namedArgs = 0;
        IntPtr signature = caRecord.blob.Signature;
        IntPtr blobEnd = (IntPtr) (((void*) signature) + caRecord.blob.Length);
        if (FilterCustomAttributeRecord(caRecord, metadataImport, ref lastAptcaOkAssembly, decoratedModule, decoratedMetadataToken, attributeFilterType, mustBeInheritable, attributes, derivedAttributes, out attributeType, out ctor, out flag2, out flag3))
        {
            if (!ctor.IsNullHandle())
            {
                ctor.CheckLinktimeDemands(decoratedModule, decoratedMetadataToken);
            }
            RuntimeConstructorInfo.CheckCanCreateInstance(attributeType, flag3);
            if (flag2)
            {
                obj2 = CreateCaObject(decoratedModule, ctor, ref signature, blobEnd, out namedArgs);
            }
            else
            {
                obj2 = attributeType.TypeHandle.CreateCaInstance(ctor);
                if (Marshal.ReadInt16(signature) != 1)
                {
                    throw new CustomAttributeFormatException();
                }
                signature = (IntPtr) (((void*) signature) + 2);
                namedArgs = Marshal.ReadInt16(signature);
                signature = (IntPtr) (((void*) signature) + 2);
            }
            for (int j = 0; j < namedArgs; j++)
            {
                string str;
                bool flag4;
                Type type3;
                object obj3;
                IntPtr ptr1 = caRecord.blob.Signature;
                GetPropertyOrFieldData(decoratedModule, ref signature, blobEnd, out str, out flag4, out type3, out obj3);
                try
                {
                    if (flag4)
                    {
                        if ((type3 == null) && (obj3 != null))
                        {
                            type3 = (obj3.GetType() == typeof(RuntimeType)) ? typeof(Type) : obj3.GetType();
                        }
                        RuntimePropertyInfo property = null;
                        if (type3 == null)
                        {
                            property = attributeType.GetProperty(str) as RuntimePropertyInfo;
                        }
                        else
                        {
                            property = attributeType.GetProperty(str, type3, Type.EmptyTypes) as RuntimePropertyInfo;
                        }
                        RuntimeMethodInfo setMethod = property.GetSetMethod(true) as RuntimeMethodInfo;
                        if (setMethod.IsPublic)
                        {
                            setMethod.MethodHandle.CheckLinktimeDemands(decoratedModule, decoratedMetadataToken);
                            setMethod.Invoke(obj2, BindingFlags.Default, null, new object[] { obj3 }, null, true);
                        }
                    }
                    else
                    {
                        (attributeType.GetField(str) as RtFieldInfo).InternalSetValue(obj2, obj3, BindingFlags.Default, Type.DefaultBinder, null, false);
                    }
                }
                catch (Exception exception)
                {
                    throw new CustomAttributeFormatException(string.Format(CultureInfo.CurrentUICulture, Environment.GetResourceString(flag4 ? "RFLCT.InvalidPropFail" : "RFLCT.InvalidFieldFail"), new object[] { str }), exception);
                }
            }
            if (!signature.Equals(blobEnd))
            {
                throw new CustomAttributeFormatException();
            }
            attributes[length++] = obj2;
        }
    }
    frame.Pop();
    if ((length == customAttributeRecords.Length) && (pcaCount == 0))
    {
        return attributes;
    }
    if (length == 0)
    {
        Array.CreateInstance(elementType, 0);
    }
    object[] destinationArray = Array.CreateInstance(elementType, (int) (length + pcaCount)) as object[];
    Array.Copy(attributes, 0, destinationArray, 0, length);
    return destinationArray;
}

在这里我们可以见数组的创建CreateInstance等等。

   同时可以参见老赵前辈以前的关于Attribute反射的一次失败的尝试(上):原来GetCustomAttributes方法每次都返回新的实例一次失败的尝试(下):无法使用泛型的Attribute

   不知道为什么在Attribute参数的检查是在我们的编译时期,参数必须是常量表达式,却在这里需要每次反射。

   本篇随笔只是个人使用心得记录,请勿拍砖。

作者:破  狼 
出处:http://www.cnblogs.com/whitewolf/ 
本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。该文章也同时发布在我的独立博客中-个人独立博客博客园--破狼51CTO--破狼。http://www.cnblogs.com/whitewolf/archive/2012/03/28/2420521.html

时间: 2024-10-12 04:26:54

Attribute鲜为人知的两个特性记录的相关文章

浅析目标市场的两大特性:可定位性和可营销性

中介交易 http://www.aliyun.com/zixun/aggregation/6858.html">SEO诊断 淘宝客 云主机 技术大厅 互联网的快速发展为我们提供了各种各样的便利,但对于很多站长来说同时也是一种压力,因为大量日常消费品的竞争已经达到白热化,所以部分站长选择了相对容易进入的利基市场.不过找到一个利基市场后,还不能马上进入,必须考虑这个目标市场是否在网上?用户是否能集中定位?是否真的有用户存在?总体来说就是目标市场的两大特性:可定位性和可营销性. 首先,可定位性:

ECMAScript 2016 获得批准,主要增加两新特性

Ecma国际批准了第七版的ECMAScript语言规范(ECMAScript 2016).ECMAScript是标准化的JavaScript语言,1997年发布了第一版,1998年和1999年发布了第二和第三个版本,之后ECMAScript沉寂 了许多年,直到Ajax流行起来后标准工作才再次起步,2009年发布了第五个版本,2015年发布了第六个版本,第七个版本又被称为ECMAScript 2016,与第六个版本相比变化并不多,主要是增加了两个新特性:Array.prototype.includ

产品定价的两大特性和八个步骤

经理们最头疼的营销问题是什么?定价.一方面,经理们觉得定价有时不受自己控制,而是为市场所左右;另一方面,也很难给定价设目标并衡量定价工作的好坏.尽管如此,我们还是要做出尽可能"正确"的定价,因为这会为公司带来巨大的收益. 本文作者通过观察并参与各种情况下的定价过程,发现了成功定价的2个特性和改进定价过程的8个步骤.一般来说,如果按这些标准行事,经理们将能定出更合适的价格,为公司带来更大的收益,并且自己也能够获得对定价的控制权. &http://www.aliyun.com/zi

逻辑卷管理的两个错误记录

在使用lvm时遇到几个问题记录一下,如你也刚好碰到,可以减少点排错时间. 1. 创建lv时报错,可能是以前这个vg的数据有问题,不过它这里有个提示. Cannot change VG vgdata01 while PVs are missing. Consider vgreduce --removemissing. 确实,在列出PV时,报了一个unknown device. pvs unknown device vgdata01 lvm2 a-m 5.82t 0 所以在这个vg上创建100%VG

关于C# 中的Attribute 特性

Attribute与Property 的翻译区别 Attribute 一般译作"特性",Property 仍然译为"属性". Attribute 是什么 Attribute 是一种可由用户自由定义的修饰符(Modifier),可以用来修饰各种需要被修饰的目标. 简单的说,Attribute就是一种"附着物" -- 就像牡蛎吸附在船底或礁石上一样. 这些附着物的作用是为它们的附着体追加上一些额外的信息(这些信息就保存在附着物的体内)-- 比如&qu

一起谈.NET技术,关于C# 中的Attribute 特性

Attribute与Property 的翻译区别 Attribute 一般译作"特性",Property 仍然译为"属性". Attribute 是什么 Attribute 是一种可由用户自由定义的修饰符(Modifier),可以用来修饰各种需要被修饰的目标. 简单的说,Attribute就是一种"附着物" -- 就像牡蛎吸附在船底或礁石上一样. 这些附着物的作用是为它们的附着体追加上一些额外的信息(这些信息就保存在附着物的体内)-- 比如&qu

“.NET研究”关于C# 中的Attribute 特性

Attribute与Proper上海企业网站制作ty 的翻译区别 Attribute 一般译作"特性",Property 仍然译为"属性". Attribute 是什么 Attribute 是一种可由用户自由定义的修饰符(Modifier),可以用来修饰各种需要被修饰的目标. 简单的说,Attribute就是一种"附着物" -- 就像牡蛎吸附在船底或礁石上一样. 这些附着物的作用是为它们的附着体追加上一些额外的信息(这些信息就保存在附着物的体内)

[C#]Attribute特性

简介       特性提供功能强大的方法,用以将元数据或声明信息与代码(程序集.类型.方法.属性等)相关联. 特性与程序实体关联后,即可在运行时使用名为"反射"的技术查询特性. 特性具有以下属性: 特性可向程序中添加元数据. 元数据是有关在程序中定义的类型的信息. 所有的 .NET 程序集都包含指定的一组元数据,这些元数据描述在程序集中定义的类型和类型成员. 可以添加自定义特性,以指定所需的任何附加信息.  可以将一个或多个特性应用到整个程序集.模块或较小的程序元素(如类和属性). 特

Attribute(特性),怎么用才更好?

  前几年: 2008年的某一天,我坐火车去北京.硬卧上铺,一晚上就到北京了.爬到上铺之后发现,旁边上铺有一老兄抱着一个笔记本,一开始还以为是看电影呢,仔细一看才发现--老天呀,居然在写代码!   这老兄也太工作狂了,当时可是晚上九点多了呀.屏幕里的IDE和vs有一点像,但又不是.问过了之后才知道,原来是大名鼎鼎的java(具体叫啥记不清楚了,好像是j2ee,对java相当的不熟,就是那个意思了).遇到java高手了,不能错失良机,要问问心中的疑问.   于是我就问他"听说java都在用Hibe