c# 特性(Attribute)

       c#中的特性本质上都是一个类。所有我们自定义的特性都派生于Attribute基类。

       仅仅定义特性类,并应用自己想要的所有势力。这样做除了在程序集中生成额外的元数据,没有其他的任何意义。应用程序代码的行为不会有任何的改变。

        FCL提供了很多种方式来检测特性的存在。为了简化讨论,让我们聚焦于System.Reflection.CustomAttributeExtensions类定义的扩展方法。该类定义了三个静态方法来获取与目标关联的特性: IsDefined, GetCustomAttributes和GetCustomAttribute。每个方法都有几个重载版本。例如:每个方法都有一个版本能操作类型成员(类、结构、枚举、接口、委托、构造器、方法、属性、字段、事件和返回类型)。这些方法在元数据上反射以查找与CLS相容的定制特性类型的实例。

     

只判断一个特性是否存在

         如果只是想判断目标是否应用了一个特性,那么应该调用IsDefined,因为它比另两个方法更高效。但是我们知道,将特性应用于目标时,可以为特性构造器指定参数,并可选择设置字段和属性。使用IsDefined不会构造特性对象,不会调用构造器,也不会设置子段和属性。

        //类型是否应用了AccountsAttribute类型的实例
        public void IsAttribute()
        {
            if (this.GetType().IsDefined(typeof(AccountsAttribute), false))
            {
                //如果是,执行的代码
            }
            else
            {
                //如果不是,执行的代码
            }
        }

 

 

两个特性实例的相互匹配

       通过构造attribute类型的一个实例,并把它初始化成我们要显示查找的内容。将构造的类型和应用的特性类型进行比较,来判定是否应用一个特性类型。

       System.Attribute重写了Object的Equals方法,该方法会在内部比较两个对象的类型。不一致会返回false。如果一致,Equals会利用反射来比较两个特性对象中的字段值(为每个字段都调用Equals)。所有字段都匹配就返回true,否者返回false。可在自己的定制特性类中重写Equals来移除反射的使用,从而提升性能。

       System.Attribute还公开了虚方法Match,可重写它来提供更丰富的语义。Match的默认实现只是调用Equal方法并返回他的错误结构。

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

    [AttributeUsage(AttributeTargets.Class)]
    public class AccountsAttribute: Attribute
    {
        private Accounts _accounts;
        public AccountsAttribute(Accounts accounts)
        {
            _accounts = accounts;
        }

        public override bool Match(object obj)
        {
            if (obj == null)
            {
                return false;
            }
            if (this.GetType() != obj.GetType())
            {
                return false;
            }
            AccountsAttribute other = (AccountsAttribute)obj;
            if ((other._accounts & _accounts) != _accounts)
            {
                return false;
            }
            return true;
        }

        public override bool Equals(object obj)
        {
            if (obj == null)
            {
                return false;
            }
            if (this.GetType() != obj.GetType())
            {
                return false;
            }
            AccountsAttribute other = (AccountsAttribute)obj;
            if (other._accounts != _accounts)
            {
                return false;
            }
            return true;
        }
    }

 

    [Accounts(Accounts.Savings)]
    internal sealed class ChildAccount
    {

    }

 

    

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

        private static void CanWriteCheck(Object obj)
        {
            //构造attribute类型的一个实例,并把它初始化成
            //我们要显示查找的内容
            Attribute checking = new AccountsAttribute(Accounts.Checking);

            //构造应用于类型的特性实例
            Attribute validAccounts = Attribute.GetCustomAttribute(obj.GetType(), typeof(AccountsAttribute), false);

            if ((validAccounts != null) && checking.Match(validAccounts))
            {
                Console.WriteLine("{0} types can write checks", obj.GetType());
            }
            else
            {
                Console.WriteLine("{0} types can NOT write checks", obj.GetType());
            }
        }
    }

 

 

检测定制特性时不创建从Attribute派生的对象

      在某些安全性要求严格的场合,这个技术能保证不执行从Attribute派生的类中的代码。毕竟,调用Attribute的GetCustomAttribute或者GetCustomAttributes方法时,这些方法会在内部调用特性类的构造器,而且可能调用属性的set访问器方法。

        可用 System.Reflection.Custom.AttributeData 类在查找特性的同时禁止执行特性类中的代码。该类定义了静态方法GetCustomAttributes来获取与目标关联的特性。方法有四个重载版本,分别获取一个 Assembly, Module, ParameterInfo 和 MemberInfo。

    class Program
    {
        static void Main(string[] args)
        {
            //显示应用于这个类型的特性集
            ShowAttributes(typeof(AccountsAttribute));

            //获取与类型关联的方法集
            var members = from m in typeof(AccountsAttribute).GetTypeInfo().DeclaredMembers.OfType<MethodBase>()
                          where m.IsPublic
                          select m;
            foreach (MemberInfo member in members)
            {
                //显示应用于这个成员的特性集
                ShowAttributes(member);
            }

            Console.ReadKey();
        }

        private static void ShowAttributes(MemberInfo attributeTarget)
        {
            IList<CustomAttributeData> attributes = CustomAttributeData.GetCustomAttributes(attributeTarget);
            Console.WriteLine("Attributes applied to {0}, {1}", attributeTarget.Name, (attributes.Count == 0 ? "None" :                                     String.Empty));

            foreach (CustomAttributeData attribute in attributes)
            {
                //显示所应用的每个特性的类型
                Type t = attribute.Constructor.DeclaringType;
                Console.WriteLine(" {0}", t.ToString());
                Console.WriteLine("Constructor called={0}", attribute.Constructor);

                IList<CustomAttributeTypedArgument> posArgs = attribute.ConstructorArguments;
                Console.WriteLine(" Positional arguments passed to constructor:" + ((posArgs.Count == 0) ? " None" : String.Empty));
                foreach (CustomAttributeTypedArgument pa in posArgs)
                {
                    Console.WriteLine(" Type={0}, Value={1}", pa.ArgumentType, pa.Value);
                }

                IList<CustomAttributeNamedArgument> namedArgs = attribute.NamedArguments;
                Console.WriteLine("  Named arguments set after construction:" + (namedArgs.Count == 0 ? "None" : String.Empty));
                foreach (CustomAttributeNamedArgument na in namedArgs)
                {
                    Console.WriteLine(" Name={0}, Type={1}, Value={2}", na.MemberInfo.Name, na.TypedValue.ArgumentType,                                 na.TypedValue.Value);
                }
                Console.WriteLine();
            }
            Console.WriteLine();
        }

   }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值