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  
      {  getset; }  
  } 

  

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);  
    }  

}

输出为: 

111

这里我们可以很清晰的看见当传入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,  0as  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( trueas RuntimeMethodInfo; 
                         if (setMethod.IsPublic) 
                        { 
                            setMethod.MethodHandle.CheckLinktimeDemands(decoratedModule, decoratedMetadataToken); 
                            setMethod.Invoke(obj2, BindingFlags.Default,  nullnew  object[] { obj3 },  nulltrue); 
                        } 
                    } 
                     else 
                    { 
                        (attributeType.GetField(str)  as RtFieldInfo).InternalSetValue(obj2, obj3, BindingFlags.Default, Type.DefaultBinder,  nullfalse); 
                    } 
                } 
                 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参数的检查是在我们的编译时期,参数必须是常量表达式,却在这里需要每次反射。

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




 本文转自 破狼 51CTO博客,原文链接:http://blog.51cto.com/whitewolfblog/821249,如需转载请自行联系原作者


相关文章
|
5月前
Attribute特性的原理
Attribute特性的原理
26 0
|
5月前
|
C#
c#之Attribute特性的原理
c#之Attribute特性的原理
23 0
|
Java 编译器 程序员
谈谈C++新标准带来的属性(Attribute)
从C++11开始,标准引入了一个新概念“属性(attribute)”,本文将简单介绍一下目前在C++标准中已经添加的各个属性以及常用属性的具体应用。
谈谈C++新标准带来的属性(Attribute)
|
程序员
Attribute(特性),怎么用才更好? —— 字段编号被误解了
  上一篇里(Attribute(特性),怎么用才更好? ),有人说,“坚决杜绝magic number ”,这个magic number指的就是字段编号吧,其实您误解了。   一提到字段编号,可能有些人的第一反应就是这样的用法:     Person1.2000020,或者Person1[2000020],或者ds[2000020]。
853 0
|
关系型数据库 PostgreSQL
PostgreSQL 自定义复合类型(composite type) deform引入的额外开销
标签 PostgreSQL , UDT , 自定义类型 背景 PG 允许用户自定义复合类型,自定义复合类型由多个类型组成,使用时会引入一些deform的开销。 例子 postgres=# create unlogged table t(id int, c1 tp1, c2 int); C...
2267 0
|
C# 编译器 数据格式
|
C# 编译器 数据格式