zoukankan      html  css  js  c++  java
  • 尽量使用条件属性(Conditional Attribute)而不是#if/#endif预处理

    http://www.cnblogs.com/JiangSoney/archive/2009/08/10/1543197.html


    .net框架提供了一个特性:属性(Attribute),注意:此属性非彼属性(property)(这都是翻译惹的祸)。

    .net框架提供了两种类型的Attribute属性:内置属性,自定义属性。顾名思义,内置属性是框架已经为我们开发好的在语言中置入的属性,自定义属性是用户自行定义、创建的属性。其中条件属性(Conditional Attribute)就是属于内置属性。.net框架提供了数百个预先定义好的内置属性,这就不多说了。下面简单的说一下怎么创建用户自定义属性,从而帮助我们理解什么是Attribute属性。

    首先要搞清楚:设计实现自定义属性本质就是设计实现一个自定义的类,这个类除了要满足一般类的要求外还要满足以下几个条件:

    1、继承System.Attribute;

    2、给该类添加AttributeUsageAttribute属性,限制属性类的用法,通过AttributeUsageAttribute类的AttributeTargets参数来指定属性类可以用于何处。如将属性类用于类、结构或者方法等等。

    举例说明:

    创建一个新的属性ClassInfo,记录类的创建时间。 

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
    public class ClassInfoAttribute : Attribute
    {
        private string _createDate;
    
        public ClassInfoAttribute(string createDate)
        {
            _createDate = createDate;
        }
    
        public string createDate
        {
            get
            {
                return _createDate;
            }
        }
    }

     测试类: 

    [ClassInfo("2009-08-10")]
    public class TClass
    {
        public string GetAttribute()
        {
            MemberInfo memInfo = typeof(TClass);
            Object[] attributes = memInfo.GetCustomAttributes(
                typeof(ClassInfoAttribute), false);
            if (0 != attributes.GetLength(0))
            {
                ClassInfoAttribute item = attributes[0] as ClassInfoAttribute;
                if (null != item)
                {
                    return item.createDate;
                }
            }
            return string.Empty;
        }
    
        [Conditional("DEBUG")]
        public virtual void TestAtDebug()
        {
            Console.WriteLine("Test at debuging condition.");
        }
    
        public void Test()
        {
            Console.WriteLine("Test at normal condition.");
        }
    }

    至此我们应该对Attribute属性大体了解了。下面来看看条件属性(Conditional Attribute)到底是怎么回事。

    [Conditional("DEBUG")]
    public virtual void TestAtDebug()
    {
        Console.WriteLine("Test at debuging condition.");
    }
    
    public void Test()
    {
        Console.WriteLine("Test at normal condition.");
    }

    在debug环境下执行的结果是:

    Test at debuging condition.
    Test at normal condition.

    在release环境下执行的结果是:

    Test at normal condition.

     

    条件属性是定义方法的运行环境的。条件属性只能在方法上使用。使用条件属性的方法必须符合以下规则:
    1、 该方法必须是某个类中的方法;
    2、 该方法不能是override方法,但可以是virtual方法。注意:当该方法是virtual方法时,则在派生类中对应的override方法也具有这个属性;
    3、 该方法返回的类型必须是void类型;
    4、 该方法不能是接口的实现。
    上面讲到条件属性只能在方法上使用,所以你应该用条件属性来修饰在不同条件下使用的方法,只有当你要在不同条件下使用一块代码时才用#if/#endif快修饰,即使这样你也应该将该段代码封装到一个方法中。
    再来看个例子:

    public class Name
    {
        private string _firstName;
        public string FirstName
        {
            set
            {
                CheckName2(value);
                _firstName = value;
            }
        }
    
        private void CheckName1(string item)
        {
    #if DEBUG
            Debug.Assert(!string.IsNullOrEmpty(item), "Name cannot be empty!");
    #endif
        }
    
        [Conditional("DEBUG")]
        private void CheckName2(string item)
        {
            if (string.IsNullOrEmpty(item))
                Console.WriteLine("Name cannot be empty!");
        }
    
    }

    虽然CheckName1和CheckName2的功能一样,但是你肯定会更愿意选择CheckName2方法。
    下面是Release编译的程序集被反编译后的结果:

    #if DEBUG/#endif


    [Conditional("DEBUG")]


    #if DEBUG/#endif只有在debug环境下才会被编译、执行。当编译器遇到#if语句后,编译器会检查与编译环境相关的符号是否存在,如果存在,就编译#if块中的代码,如果不存在,编译器会忽略之后的代码直到#endif。当采用Conditional属性时,不管DEBUG环境变量是否被定义,Conditional属性修饰的方法总会被编译到程序集中。这或许看上去是低效的,但这只是占用一点硬盘空间,且该方法不会被载入到内存,更不会被编译成机器代码,除非它被调用。这样做的好处是生成更高效的IL(中间语言Intermediate Language)代码,从而增强程序的可伸缩性,唯一不足的是带来了一点微不足道的硬盘空间开销。
    另外,如果过多的在程序块中添加#if/#endif块,使#if/#endif块与普通代码混在一起,容易造成程序结构的混乱,晦涩难懂。并且在调试完之后,为了使用户不会被这些调试信息弄糊涂,还需要把这些#if/#endif一个一个的去掉,这样不仅不方便而且容易引发错误。#if/#endif的这些缺点正好是Conditional属性的优点。至于Conditional属性限制方法的返回类型只能是void类型,不适应返回非void类型的方法,如果你一定要这样做,别忘了可以给方法传递out类型的参数。


    总之:Conditional属性跟#if/#endif预处理比起来,具有以下几点优势:
    1、可以由定义标记来灵活的控制;
    2、可以生成更高效的IL代码;
    3、帮助你强制在条件代码上使用更好的结构;
    4、可以避免因使用#if/#endif而产生的常见的错误;
    5、能更好的区分条件代码和普通代码。

  • 相关阅读:
    C++ const用于iterator
    C++实现类似python中的字符串split函数
    简单地解释overwrite
    ubuntu16.04 新安装的系统启动ssh服务
    强化学习7日打卡营-世界冠军带你从零实践--基于表格型方法的 RL
    spark-遇到问题小结
    Spark 读写hive 表
    spark-shell 显示乱码
    机器学习-GBDT和XGboost
    链表
  • 原文地址:https://www.cnblogs.com/gsk99/p/4939401.html
Copyright © 2011-2022 走看看