zoukankan      html  css  js  c++  java
  • clr via c# 定制特性

    1,特性的应用范围:特性可应用于程序集,模块,类型,字段,方法,方法参数,方法返回值,属性,参数,泛型参数

    2,利用前缀告诉编译器表明意图---下面的倾斜是必须的表明了我们的目标元素:

    [assembly: AssemblyTitle("ClrFromCSharp_2_2")]
    [assembly: AssemblyDescription("")]
    [assembly: AssemblyConfiguration("")]
    [assembly: AssemblyCompany("")]
    [assembly: AssemblyProduct("ClrFromCSharp_2_2")]
    [assembly: AssemblyCopyright("Copyright ©  2020")]
    [assembly: AssemblyTrademark("")]
    [assembly: AssemblyCulture("")]
    
    // 将 ComVisible 设置为 false 会使此程序集中的类型
    //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
    //请将此类型的 ComVisible 特性设置为 true。
    [assembly: ComVisible(true)]
    
    // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
    [assembly: Guid("8c81c6c1-261e-445a-827d-fabe71033d57")]
    
    // 程序集的版本信息由下列四个值组成: 
    //
    //      主版本
    //      次版本
    //      生成号
    //      修订号
    //
    //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
    //通过使用 "*",如下所示:
    // [assembly: AssemblyVersion("1.0.*")]
    [assembly: AssemblyVersion("1.0.0.0")]
    [assembly: AssemblyFileVersion("1.0.0.0")]

    3,特性的本质是一个类型的实列,并且定制特性类必须从System.Attribute类派生

    4,许多类:比如

    StructLayoutAttribute

    MarshalAsAttribute

    DllImportAttribute

    InAttribute

    OutAttribute

    都在命名空间System.Runtime.InteropServices命名空间中.

    5,特性对象的构造,应为特性是类的实列,所以其支持类似

    [DllImport("avifil32.dll"),CharSet=CharSet.Ansi)]//其中第一个为构造器参数,第二个为公共字段的值
    private static extern void AVIFileInit();

    6,定制特性的简化写法,

    • 两个定制特性可以分开写也可以写一起(使用","分开)
    • 定制特性没有先后顺序的区分
    • 定制特性如果没有构造器参数,可以省略()
    • 定制特性如果后缀是Attribute,可以省略,以下都一样.
      [Serializable][Flags]
      [Serializable,Flags]
      [FlagsAttribute,SerializableAttribute]
      [FlagsAttribute(),SerializableAttribute()]

    7,定义自己的特性类

        假设需要定义类FlagsAttribute

    [AttributeUsage(AttributeTargets.Enum,Inherited =false)]
        public class FlagsAttribute : Attribute
        {
            public FlagsAttribute() { }
        }

    注意上面的AttributeUsage类

    • 定制参数指明该定制特性的范围--AttributeTargets--比如Flags只能作用于枚举类
    • 指定是否可以将特性用于同一目标 AllowMultiple
    • 指定是否将特性应用于派生类和重写的方法:Inherited
    • 特性类的实列构造器,字段和属性能用的数据类型并不多,只允许
    • Boolean,Char,Byte,SByte,Int16,UInt16,Int32,UInt32,Int64,UInt64,Single,Double,String,Type,Object,Enum.
    • 还可以使用上述类型的一维0基数组,但是应尽量避免使用数组.

    8,检测定制特性

     [AttributeUsage(AttributeTargets.All,Inherited =false)]
        public class Flags1Attribute : Attribute
        {
            public Flags1Attribute() { }
        }
       // [Flags1]
        public class TestAttribute
        {
            public TestAttribute()
            {
                if (this.GetType().IsDefined(typeof(Flags1Attribute), false))
                    Console.WriteLine("the object is Defined the Attribute Flags1");
                else
                    Console.WriteLine("the object is not Defined the Attribute Flags1");
    
            }
            public static void Call()
            {
                TestAttribute a1 = new TestAttribute();
    
            }
        }

    使用IsDefined函数检测在类的实列中是否使用了特性!注意该方法在MemberInfo类中定义,注意,类Type派生自该类.

    • IsDefined()该方法检测是否由指定的Attribute派生类的实列与目标关联
    • GetCustomAttribute()---获取特性常用于multiple设为true
      public static void Main()
          {
              try
              {
                  // Get the type of MyClass1.
                  Type myType = typeof(MyClass1);
                  // Get the members associated with MyClass1.
                  MemberInfo[] myMembers = myType.GetMembers();
      
                  // Display the attributes for each of the members of MyClass1.
                  for(int i = 0; i < myMembers.Length; i++)
                  {
                      Object[] myAttributes = myMembers[i].GetCustomAttributes(true);
                      if(myAttributes.Length > 0)
                      {
                          Console.WriteLine("
      The attributes for the member {0} are: 
      ", myMembers[i]);
                          for(int j = 0; j < myAttributes.Length; j++)
                              Console.WriteLine("The type of the attribute is {0}.", myAttributes[j]);
                      }
                  }
              }
              catch(Exception e)
              {
                  Console.WriteLine("An exception occurred: {0}", e.Message);
              }
          }

    当使用GetMembers方法可以获取某个类的所有公开类型,注意,方法,属性,字段,构造器等都是Member之一.

    然后利用分别对每一个成员获取其特性属性集合.

    9,CustomAttributeExtensions中定义的三个方法

    方法名称

    说明
    IsDefined
    public static bool IsDefined (this System.Reflection.MemberInfo element, Type attributeType, bool inherit);//inherit指定是否检查其上级,true则检查,false不检查
    public static bool IsDefined (this System.Reflection.Assembly element, Type attributeType);
    //检查某个程序集里面是否存在该特性
    public static bool IsDefined (this System.Reflection.MemberInfo element, Type attributeType);
    //检查某个类的成员是否包含特定的特性
    public static bool IsDefined (this System.Reflection.Module element, Type attributeType);
    //检查某个模块里面是否包含特定的特性
    public static bool IsDefined (this System.Reflection.ParameterInfo element, Type attributeType);
    //检查某个方法里面的参数是否包含特定的特性
    
    GetCustomAttributes

    与上述类似,用于获取某个对象(模块,程序集,type,memberinfo,parameterinfo,等)的特性的集合.

    返回一个枚举集合.

    GetCustomAttribute
    public static Attribute GetCustomAttribute (this System.Reflection.Assembly element, Type attributeType);//从某个对象里面直接获取这个特性实列.

    10,反射命名空间 System.Reflection 提供了几个类允许检查模块的元数据

    • Assembly
    • Module
    • ParameterInfo
    • MemberInfo
    • Type
    • MethodInfo
    • ConstructorInfo
    • FieldInfo
    • EventInfo
    • PropertyInfo
    • 及各自的*Builder类

    所有类都提供了IsDefined和GetCustomAttributes方法.

    11,检测定制特性 注意----MemberInfo--->Type---->TypeInfo.

    利用Type

    可以获得

    • 类的方法
    • 类的成员
    • 类的字段
    • 类的属性
    • 类的构造器等
    TypeInfo t = typeof(Calendar).GetTypeInfo();
                IEnumerable<PropertyInfo> pList = t.DeclaredProperties;
                IEnumerable<MethodInfo> mList = t.DeclaredMethods;

    查看定制类的方法:

    [Serializable]
        [DefaultMember("Main")]
        [DebuggerDisplay("Maoxiongbin",Name ="Mao",Target =typeof(CheckAttributeRef))]
        public sealed class CheckAttributeRef//上面特性用于定义类的特性.
        {
            [Conditional("Debug")]
            [Conditional("Release")]
            public void DoSomething() { }//上面两个特性用于定义Dosomething方法
            public CheckAttributeRef() { }//没有特性御用构造器
    
            [CLSCompliant(true)]
            [STAThread]
            public static void Go()//2个特性用于静态方法GO()
            {
                ShowAttributes(typeof(CheckAttributeRef));//查看奔雷的特性情况
    
                var members = from m in typeof(CheckAttributeRef).GetTypeInfo().DeclaredMembers.OfType<MethodBase>()//使用GetTypeInfo()返回TypeInfo对象,然后调用
                              where m.IsPublic//DeclareMembers获取其成员,然后删选必须时类别MethodBase的派生类,MethodInfo和ConstructInfo两类.....并且是公共的
                              select m;
                members.ToList<MethodBase>().ForEach(x => ShowAttributes(x));//执行特性输出
    
            }
            private static void ShowAttributes(MemberInfo AttributeTargets)
            {
                var attr = AttributeTargets.GetCustomAttributes<Attribute>();//MemberInfo是基类--是MethodInfo和ConstructInfo的基类,利用Extensions扩展函数获取成员中的特性.
                Console.WriteLine("Attribute applied to {0}:{1}", AttributeTargets.Name, (!attr.Any() ? "None" : String.Empty));//成员名称,成员中定制特性数量...
                foreach(Attribute attribute in attr)//针对不同特性输出不同信息.
                {
                    Console.WriteLine("{0}", attribute.GetType().ToString());
                    if (attribute is DefaultMemberAttribute)
                        Console.WriteLine("MemberName={0}", ((DefaultMemberAttribute)attribute).MemberName);
                    if (attribute is ConditionalAttribute)
                        Console.WriteLine("ConditionString={0}", ((ConditionalAttribute)attribute).ConditionString);
                    if (attribute is CLSCompliantAttribute)
                        Console.WriteLine("IsCompliant={0}", ((CLSCompliantAttribute)attribute).IsCompliant);
                    if(attribute is DebuggerDisplayAttribute)
                    {
                        DebuggerDisplayAttribute d = (DebuggerDisplayAttribute)attribute;
                        Console.WriteLine("Value={0},Name={1},Target={2}", d.Value, d.Name, d.Target);
                    }
    
                }
                Console.WriteLine();
            }
        }
    }

    12,类的特性匹配

        12.1新建一个枚举类型 Accounts

    [Flags]
        internal enum Accounts
        {
            Savings=0x0001,
            Checking=0x0002,
            Brokerage=0x0004
        }

    12.2新建一个账号等级特性

     [AttributeUsage(AttributeTargets.Class)]//该特性只能在类上面
        internal sealed class AccountsAttribute : Attribute//定义Accounts特性
        {
            private Accounts m_accounts;
            public AccountsAttribute(Accounts accounts)//构造函数
            {
                m_accounts = accounts;
            }
            public override bool Match(object obj)//重写Match函数,定义匹配特性.
            {
                if (obj == null) return false;//如果obj是null则返回
                if (this.GetType() != obj.GetType()) return false;//如果类型不匹配,则返回.
                var other = obj as AccountsAttribute;
                if ((other.m_accounts & m_accounts) != m_accounts)//判断other的m_accounts是否包含了this.m_accounts的信息.
                    return false;
                return true;
            }
            public override bool Equals(object obj)//重写该函数,检查两个特性是否相等.
            {
                if (obj == null) return false;
                if (this.GetType() != obj.GetType()) return false;
                var other = obj as AccountsAttribute;
                return other.m_accounts == m_accounts;
            }
    
            public override int GetHashCode()//重写了Equals,必须重写该函数.
            {
                return (int)m_accounts;
            }
        }
        [Accounts(Accounts.Savings)]
        internal sealed class ChildAccount { }//定义测试的类,并且定制特性对象Accounts,初始化为Accounts.Savings.
        [Accounts((Accounts)7)]//定义测试的类,并且定制特性对象Accounts,初始化为Accounts.Savings|Checking|Brokerage
        internal sealed class AdultAccount { }//(Accounts)7进行转换.
    

    12.3创建一个测试函数

      private static void CanWriteCheck(object obj)
            {
                Attribute checking = new AccountsAttribute(Accounts.Checking);//创建特性类对象
                Attribute validAccounts = obj.GetType().GetCustomAttribute(typeof(AccountsAttribute));//从类中获取嵌入的特性类对象
                if ((validAccounts != null) && (checking.Match(validAccounts)))//利用Match函数判断是否符合条件
                    Console.WriteLine("{0} types can  write checks.", obj.GetType());
                else
                    Console.WriteLine("{0} types can  not write checks.", obj.GetType());
    
            }

    `12.4测试和结果

    public static void GoAttributeMatch()
            {
                CanWriteCheck(new ChildAccount());//测试CHild类
                CanWriteCheck(new AdultAccount());//测试Adult类
                CanWriteCheck(new CheckAttributeRef());//测试CHeck类
            }
    //结果

    ClrFromCSharp_2_2.LearnAttribute.ChildAccount types can  not write checks.
    ClrFromCSharp_2_2.LearnAttribute.AdultAccount types can  write checks.//类的特性中由checking
    ClrFromCSharp_2_2.LearnAttribute.CheckAttributeRef types can  not write checks.

    //
    //
    //

    13,条件特性类----在特性类前面加入 特[Conditional("Test1"),Conditional("Test2")] 来控制,只有在当前文件下,定义了

    #define Test1 或者 #define Test2 才能够生成特性实列.

    [Conditional("TEST"),Conditional("VERIFY")]
        [AttributeUsage(AttributeTargets.All)]
        public sealed class CondAttribute : Attribute
        {
    
        }

    也就是说,特性CondAttribute只有在由#define Test 或者#define VERIFY的情况下才有效

    public sealed class CondTest
        {
            public static void Go()
            {
    
                Console.WriteLine("CondAttribute is {0} applied to {1} type", (typeof(CondTest).IsDefined(typeof(CondAttribute),false)) ? "" : "not", typeof(CondTest).ToString());
            }
        }
    当定义了的时候,能够检测到特性Cond,当都未定义的时候(注释掉#define test,#define verify)则 检测不到Cond.
  • 相关阅读:
    hihoCoder week20 线段树的区间修改
    hihoCoder week19 RMQ问题再临-线段树 单点更新 区间查询
    hihoCoder week17 最近公共祖先·三 lca st表
    hihoCoder week16 RMQ-ST算法
    hihoCoder week15 最近公共祖先·二
    eclipse 分屏显示同一文件
    eclipse 每次以debug方式启动springboot之后都会在SilentExitExceptionHandler类中的throw new SilentExitException()处断开,但是我明明没有下断点啊
    eclipse alt+/智能提示错误问题
    SpringBoot 之 普通类获取Spring容器中的bean
    kafka常用命令
  • 原文地址:https://www.cnblogs.com/frogkiller/p/12290340.html
Copyright © 2011-2022 走看看