zoukankan      html  css  js  c++  java
  • Attribute鲜为人知的两个特性记录

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

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

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

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

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

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

    View Code
    [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):

    View Code
    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参数的检查是在我们的编译时期,参数必须是常量表达式,却在这里需要每次反射。

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

  • 相关阅读:
    Algebra, Topology, Differential Calculus, and Optimization Theory For Computer Science and Machine Learning 第4章 读书笔记(待更新)
    Algebra, Topology, Differential Calculus, and Optimization Theory For Computer Science and Machine Learning 第3章 读书笔记(待更新)
    Algebra, Topology, Differential Calculus, and Optimization Theory For Computer Science and Machine Learning 第1,2章 读书笔记(待更新)
    Tkinter的Message组件
    Git 实操/配置/实践
    mysq5.7.32-win安装步骤
    行为型模式之模板方法
    结构型模式之组合模式
    结构型模式之享元模式
    结构型模式之外观模式
  • 原文地址:https://www.cnblogs.com/whitewolf/p/2420521.html
Copyright © 2011-2022 走看看