zoukankan      html  css  js  c++  java
  • CLR笔记:17.自定义属性

    自定义属性,使用声明式编程的方式,HTML也是属于这种编程方式。
    17.1    使用自定义属性
    只是将一些附加信息与某个目标元素关联起来。编译器在托管模块的元数据中生成额外的信息。
    从System.Attribute派生,所有符合CLS的属性都是从这个基类派生。
    有定位参数和命名参数两种,前者必须指定。
    可以将多个属性应用于单个目标元素,用逗号分割。

    17.2    定义自己的属性
        属性类标准写法:
        [AttributeUsage(AttributeTargets.Enum, Inherited = true, AllowMultiple = false)]
        
    public class FlagAttribute : System.Attribute
        
    {
            
    public FlagAttribute() { }
        }

        注意:1.属性就是类的一个实例,因此属性类至少要有一个公共构造器。如果class没有ctor,就生成默认ctor,所以也可以编译通过。
                    2.这个类不要提供任何公共方法/事件
                    3.FlagAttribute使用的时候,可以简写为[Flag]
                    4.AttributeTarget枚举,限定属性的应用范围,上面程序说明Flag只能用于Enum类型;AttributeTarget.All表示适用于所有类型。
                    5.AllowMultiple指出是否可以将属性多次应用于单个目标:
                        大部分属性只能使用一次,如以下代码会编译出错,因为没有任何意义:

        [Flag]
        [Flag]
        
    public enum Color
        

            Red
        }

                        少数属性有必要将属性多次应用于单个目标,如Conditional属性类(见17.7)
                    6.Inherited指出属性是否能由派生类和重写成员继承,如下代码:

        [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true)]
        
    internal class TastyAttribute : System.Attribute
        
    {
            
    public TastyAttribute() { }
        }


        [Tasty][Serializable]
        
    internal class BaseType
        
    {
            [Tasty]
            
    protected virtual void DoSomething() { }
        }


        
    internal class DeriveType : BaseType
        
    {
            
    protected override void DoSomething() { }
        }

                        这里,因为继承的关系,DerivedType及其方法都有属性[Tasty]。由于Serializable属性被标记为不可继承,所以DerivedType不可以序列化。
                        只有class/method/properties/field/event/方法返回值/方法参数,是可继承的,inherited设为true。
                        Inherited属性不会为派生类生成额外的元数据,不影响派生类行为,只是在程序集中生成额外的元数据。

    补充:从AttributeUsage类的FCL源码,可以看出:
            不设置AttributeUsage属性,默认为    [AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)]

    17.3    属性的ctor/Field/Property的数据类型,不能是静态的
            必须限制在尽量小的类型范围内。
            尽量应该避免使用,因为会在ctor中传递数组参数,不兼容于CLS(非0基数组不符合CLS)
            在属性中定义Type类型,要使用typeof()方法传递参数;定义Object类型,可以传递Int32/String等常量表达式(包括null)如果常量表达式为值类型,则执行时需要装箱。

        public enum Color { Red }

        
    class SomeAttribute : Attribute
        
    {
            
    public SomeAttribute(String name, Object o, Type[] type) { }
        }


        [Some(
    "Jeff", Color.Red, new Type[]{typeof(Math), typeof(Console)})]
        
    class SomeType { }

    17.4    检测自定义属性的使用
    在枚举中,介绍了Format静态方法,功能基本同ToString()方法,但允许value传递一个数值,而不仅仅是一个Enum类型

                Enum.Format(typeof(Color), 3"G");

    这个方法的实现如下:

            public static String Format(Type enumType, Object value, String format)
            

                
    //检查枚举类型是否应用了Flag属性类型的一个实例
                
    //false表示不从其派生类中继续查找
                if(enumType.IsDefined(typeof(FlagsAttribute), false))
                
    {
                    
    //如果是,将value作为一个位标志处理
                }

                
    else
                
    {
                    
    //如果不是,将value作为一个普通枚举类型
                }

            }

    以上使用了Type的IsDefined方法,检查一个类型上的属性。

    以下介绍检查一个目标的属性:如Assembly,module,方法,有3个方法可以使用:
        1.IsDefined方法,只是检查,不构造属性类的实例,效率很高
            Attribute.IsDefine一般有两个参数,第一个是要检查的目标.GetType(),第二个是typeof(属性)。当目标是Attribute/Type/MemthodInfo时,要使用第三个参数,决定是否要从派生类查找。

        2.GetCustomAttributes方法,返回一个应用于目标的属性数组

            public static void ShowAttribute(MemberInfo attributeTarget)
            
    {
                Attribute[] attributes 
    = Attribute.GetCustomAttributes(attributeTarget);

                
    foreach (Attribute attribute in attributes)
                

                    
    //遍历属性数组
                }

            }


        3.GetCustomAttribute方法,返回应用于目标的制定属性类的一个实例,使用方法见下一节。

    17.5    两个属性实例的相互匹配
        自定义属性,要重写Match()方法,才可以比较两个属性实例,否则,会调用System.Attribute的match()方法,而后者,只是调用Mquals方法。
        实例展示了Match的重写,以及上一节GetCustomAttribute方法的使用

        [Accounts(Accounts.Savings)]
        
    class ChildAccount { }

        [Accounts(Accounts.Savings 
    | Accounts.Checking)]
        
    class AdultAccount { }

        
    class Program
        
    {
            
    static void Main(string[] args)
            
    {
                CanWriteCheck(
    new ChildAccount());
                CanWriteCheck(
    new AdultAccount());
            }


            
    private static void CanWriteCheck(Object obj)
            
    {
                Attribute checking 
    = new AccountsAttribute(Accounts.Checking);

                
    //以下语句展示了Attribute的GetCustomAttribute方法
                Attribute validAccount = Attribute.GetCustomAttribute(obj.GetType(), typeof(AccountsAttribute), false);

                
    if ((validAccount != null&& checking.Match(validAccount))
                
    {
                    
    //obj有写的权限
                }

            }

        }


        [Flags]
        
    enum Accounts
        
    {
            Savings 
    = 0x001,
            Checking 
    = 0x002,
        }


        [AttributeUsage(AttributeTargets.Class)]
        
    public class AccountsAttribute : Attribute
        
    {
            
    private Accounts m_accounts;

            
    public AccountsAttribute(Accounts accounts)
            
    {
                m_accounts 
    = accounts;
            }


            
    public override bool Match(object obj)
            
    {
                
    //如果基类实现了Match,而基类又不是System.Attribute,就取消下面这段注释
                
    //if (!base.Match(obj))
                
    //{
                
    //    return false;
                
    //}


                
    //如果基类实现Match,则下面这条语句可以删除
                
    //因为this肯定不为null,如果obj为null,则肯定不匹配
                if (obj == null)
                
    {
                    
    return false;
                }


                
    //如果基类实现Match,则下面这条语句可以删除
                
    //对象属于不同类型,肯定不匹配
                if (this.GetType() != obj.GetType())
                
    {
                    
    return false;
                }


                
    //转型一定成功,因为由上条语句,对象肯定具有相同的类型
                AccountsClass other = (AccountsClass)obj;

                //以下语句要分别比较各个字段,其中有一个不对就返回false,举一个例子:
                if ((other.m_accounts & m_accounts) != m_accounts)
                {
                    return false;
                }

                return true;


            }

        }

    17.6    查找自定义属性,同时不创建属性类(即不执行属性类的代码)
    使用System.Reflection.CustomAttributeData类,使用其静态方法GetCustomAttributes(),获取一个与目标关联的属性。4个重载版本,分别接受Assembly/Module/ParameterInfo/MemberInfo参数。
    同时要配合使用Assembly.ReflectionOnlyLoad()方法,得到程序集,然后再使用GetCustomAttributes()方法进行分析

    CustomAttributeData类的3个只读属性:
        1.Constructor,返回ctor形式:Void .ctor(String.String)    //这里表示ctor有一个String参数
        2.ConstructorArguments,泛型,要传递给ctor的参数
        3.NamedArguments,泛型,返回要设置的字段,不在ctor中设置的

            public static void ShowAttribute(MemberInfo attributeTarget)
            
    {
                IList
    <CustomAttributeData> attributes = CustomAttributeData.GetCustomAttributes(attributeTarget);

                
    foreach (CustomAttributeData attribute in attributes)
                

                    
    //遍历属性数组
                }

            }

        }


    17.7    条件属性类:使用了System.Diagnostics.ConditionalAttribute的属性类

    #define VERIFY
    using System.Diagnostics;

    [Conditional(
    "TEST")]
    [Conditional(
    "VERIFY")]
    class CondAttribute : Attribute { }

    [Cond]
    public class Program
    {
        
    static void Main()
        
    {
            Console.WriteLine(Attribute.IsDefined(
    typeof(Program), typeof(CondAttribute)));
        }

    }

    这里,#define VREIFY语句要定义在using之前,这条语句的有无,决定了CondAttribute是否会在IL中生成。


  • 相关阅读:
    书法的艺术
    书法的艺术
    matlab gabor 滤波器
    matlab gabor 滤波器
    生活中的物理学(电学)
    生活中的物理学(电学)
    CCD 与 CMOS
    CCD 与 CMOS
    博物院与国宝
    【设计模式】学习笔记13:组合模式(Composite)
  • 原文地址:https://www.cnblogs.com/Jax/p/906573.html
Copyright © 2011-2022 走看看