NET面试题:如何使用Conditional特性
优秀的代码往往在编写的时候就预先给测试留下了足够的接口,而同时又会保证程序发布后这些接口将不复存在。本节,将借助这个问题介绍Conditional这个非常实用的特性。
  所涉及的知识点
· Debug和Release版本
· Conditional特性的功能
  分析问题
通常在程序被编译时,程序员可以选择编译成Debug版本或者Release版本,正如它们的名字一样,编译器将根据“调试”和“发布”两个不同的出发点去编译程序。在Debug版本中,所有Debug类的断言语句都会得到保留,而在Release版本中,这些断言则将会被删除。这样的机制有助于为了方便程序员编写出方便调试同时又不影响正式发布的程序的代码。
断言是指形如Debug.Assert(false,"Debug.Assert");的代码,为了在程序运行过程中可以对系统进行监控和检测。
单纯的诊断和断言可能并不能完全满足调试的需求,有的时候可能会需要大批的代码和方法去支持调试和测试,这个时候,就需要用到Conditional属性。代码3-25给出了一个Conditional的使用示例。
代码3-25  Conditional特性:UseConditional.cs
namespace NET.MST.Third.UseConditional
{
    //含有两个成员,生日和身份证
    //身份证的第6位到第14位必须是生日
    //身份证必须是18位
    public class People
    {
        private DateTime _birthday;
        private String _id;
        public DateTime Birthday
        {
            //设置时检查是否符合业务逻辑
            set
            {
                _birthday = value;
                if (!Check())
                    throw new ArgumentException();
            }
            get
            {
                Debug();
                return _birthday;
            }
        }
        public String ID
        {
            //设置时检查是否符合业务逻辑
            set
            {
                _id = value;
                if (!Check())
                    throw new ArgumentException();
            }
            get
            {
                Debug();
                return _id;
            }
        }
        public People(String id,DateTime birthday)
        {
            _id = id;
            _birthday = birthday;
            Check();
            Debug();
        }
        //只希望在DEBUG版本中出现
        [Conditional("DEBUG")]
        protected void Debug()
        {
            Console.WriteLine(_birthday.ToString("yyyy-MM-dd"));
            Console.WriteLine(_id);
        }
        //检查是否符合业务逻辑
        //在所有版本中都需要
        protected bool Check()
        {
            if (_id.Length != 18 ||
                _id.Substring(6, 8) != _birthday.ToString("yyyyMMdd"))
                return false;
            return true;
        }
        static void Main(string[] args)
        {
            try
            {
                People p = new People("310101198008010031",
                    new DateTime(1980, 8, 1));
                p.ID = "310101198709080031";
            }
            catch (ArgumentException ex)
            {
                Console.WriteLine(ex.GetType().ToString());
            }
            finally
            {
                Console.Read();
            }
        }
    }
}
在代码3-25中,有两个重要的方法:Check方法和Debug方法,分别用于检查业务逻辑和打印类型状态。对于Debug方法,用了Conditional("Debug")特性来修饰,这个方法只在Debug版本中有效,而在Releaes版本中将不起作用。下面分别是Debug版本和Release版本的输出:
Debug版本:
1980-08-01
310101198008010031
System.ArgumentException
Release版本:
System.ArgumentException
Conditional的机制非常简单,在编译的时候编译器将查看编译状态和Conditional特性的参数,如果两者匹配,则将正常编译,而当两者不匹配时,编译器将简单地移除方法内的所有内容,这样就实现了Conditional的功能。
Conditional是移除方法内的内容,而不是移除调用带有Conditional特性方法的代码。所以在不匹配的情况下,代码就如同调用了一个内容为空的方法。
带有Conditional特性的方法不能申明返回值。很多资料会认为Conditional的机制导致了程序实际发布后带有无谓的空方法,对性能有影响。笔者认为,根据.NET的运行机制,调用非虚的空方法对性能的影响微乎其微,而其带给程序的灵活性却相当可观。
  答案
Conditional特性用于编写在某个特定编译版本中运行的方法,通常它编写一些在Debug版本中支持测试的方法。当版本不匹配时,编译器会把Conditional特性的方法内容置空
 

更多.net面试题,.net电子书,.net教学视频请参考"爱学网izixue"