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

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

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

CLR笔记:17.自定义属性    [Flag]
CLR笔记:17.自定义属性    [Flag]
CLR笔记:17.自定义属性    
public enum Color
    }

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

CLR笔记:17.自定义属性    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true)]
CLR笔记:17.自定义属性    
internal class TastyAttribute : System.Attribute
    }

                    这里,因为继承的关系,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)如果常量表达式为值类型,则执行时需要装箱。

{ }

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

CLR笔记:17.自定义属性            Enum.Format(typeof(Color), 3"G");

这个方法的实现如下:

CLR笔记:17.自定义属性        public static String Format(Type enumType, Object value, String format)
        }

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

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

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

CLR笔记:17.自定义属性        public static void ShowAttribute(MemberInfo attributeTarget)
        }


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

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

CLR笔记:17.自定义属性    [Accounts(Accounts.Savings)]
            //以下语句要分别比较各个字段,其中有一个不对就返回false,举一个例子:
            if ((other.m_accounts & m_accounts) != m_accounts)
            {
                return false;
            }

            return true;

CLR笔记:17.自定义属性
        }
CLR笔记:17.自定义属性    }

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中设置的

CLR笔记:17.自定义属性        public static void ShowAttribute(MemberInfo attributeTarget)
    }


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

CLR笔记:17.自定义属性#define VERIFY
CLR笔记:17.自定义属性
using System.Diagnostics;
CLR笔记:17.自定义属性
CLR笔记:17.自定义属性[Conditional(
"TEST")]
CLR笔记:17.自定义属性[Conditional(
"VERIFY")]
}

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


相关文章:

  • 2022-12-23
  • 2021-07-12
  • 2022-12-23
  • 2021-12-06
  • 2022-12-23
  • 2022-12-23
  • 2021-10-21
  • 2021-09-18
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-12-06
相关资源
相似解决方案