浅尝EffectiveCSharp_2

作者:编程技术
     [Conditional("DEBUG")]//只在Debug模式下test方法才会被调用
        public static void Test()
        {
            Console.WriteLine("Debug");
        }

Item 4:使用Conditional特性,避免#if条件编写翻译 Use Conditional Attributes Instead of #if

}

   使用#if   #endif能够在近似源码上扭转不一致的编纂(结果卡塔尔,平时是调式(debug卡塔尔国和发表(release卡塔尔国版本。

  }

   但是#if/#endif相当轻易被滥用,使得编写的代码难以驾驭和调式,所以C#提供了标准性格(Conditional attribute卡塔尔国来识别哪些方法能够依靠条件设置来判断是或不是相应被调用。

Item 3: 使用isas操作符,避免**强制转型 Prefer the is or as Operators to Casts**

    methodName,

   条件天性比标准编辑#if  #endif尤其显著知道,全部能够使用Conditional attribute

  • The correct choice is to use the as operator whenever you can because it

    is safer than blindly casting and is more efficient at runtime. The as and

    is operators do not perform any user-defined conversions. They succeed

    only if the runtime type matches the sought type; they never construct a

    new object to satisfy a request.

    应该是不择手腕地应用as操作符,因为它比强制转型要安全,而且在运作时更有成效。as和is操作符都不实践此外客户自定义的改变。独有当运营时类型与对象转移类型相称时,它们才会转变到功。它们永久不会在更动进程中结构新的目的。The correct choice is to use the as operator whenever you can because it is safer than blindly casting and is more efficient at runtime. The as and is operators do not perform any user-defined conversions. They succeed only if the runtime type matches the sought type; they never construct a new object to satisfy a request.

  • 看壹个例证,以下是八个将大肆Object类型调换到MyType类型。Take a look at an example. You write a piece of code that needs to convert an arbitrary object into an instance of MyType. You could write it this way

     1 object o = Factory.GetObject();
     2  // Version one:
     3  MyType t = o as MyType;
     4  if (t != null)
     5 {
     6  // work with t, it's a MyType.
     7  }
     8  else
     9 {
    10  // report the failure.
    11  }
    

    依然你能够如此写:

     1 object o = Factory.GetObject();
     2 // Version two:
     3 try
     4 {
     5 MyType t;
     6 t = (MyType)o;
     7 // work with T, it's a MyType.
     8 }
     9 catch (InvalidCastException)
    10 {
    11 // report the conversion failure.
    12 }
    

     

  • 转型之后要咬定是不是是null何况要捕获相当,而用as只要看再次来到的值是还是不是是null。with casts, you need to check null and catch exceptions. Using as, you simply check the returned reference against null.

  • foreach循环用的是强制转型,因为foreach供给强制转型来帮忙值类型和引用类型。foreach uses a cast operation to perform conversions from an object to the type used in the loop.foreach needs to use casts to support both value types and reference types.

上边的代码在debug版本中运作得很好,不过放到release版本中就能输出二个空行。输出一个空行本人未有何,但那终归不是大家自然的打算。我们温馨搞糟的事体,编写翻译器也帮不上什么忙,因为大家把归属程序主逻辑的代码和规范编写翻译代码混在同盟了。在源代码中放肆地选择#if和#endif将使大家很难确诊不一致版本间的一言一动差距。

总计:编写翻译器使用Conditional脾性来帮衬开采者使用#if   #endif 而爆发常规错误。条件特性比起预管理,它为不相同规范代码提供了越来越好的区分

  • 本条点子比规范编写翻译#if/#endif尤其明分明了。编写翻译器能够辨别Conditional属性,当法规属性被采纳时,编写翻译器能够很好的造成专门的职业。条件属性是在格局上接纳的,所以那就选拔你不得不把分歧规范下使用的代码要写到不一样的法子里去。  It’s a cleaner way to describe conditional compilation than #if/#endif. The compiler understands the Conditional attribute, so it can do a better job of verifying code when conditional attributes are applied. The conditional attribute is applied at the method level, so it forces you to separate conditional code into distinct methods. Use the Conditional attribute instead of #if/#endif blocks when you create conditional code blocks.

     1 private void CheckStateBad()
     2 {
     3 // The Old way:
     4 #if DEBUG
     5     Trace.WriteLine("Entering CheckState for Person"); 
     6     string methodName = new StackTrace().GetFrame(1).GetMethod().Name;
     7     Debug.Assert(lastName != null, methodName, "Last Name cannot be null");
     8     Debug.Assert(lastName.Length > 0, methodName,  "Last Name cannot be blank");
     9     Debug.Assert(firstName != null, methodName, "First Name cannot be null");
    10     Debug.Assert(firstName.Length > 0, methodName, "First Name cannot be blank");
    11     Trace.WriteLine("Exiting CheckState for Person");
    12 #endif
    13 }
    

     

  • 上面的代码中使用#if块,会在debug和release版本中确立一个空方法。Using the #if and #endif pragmas, you’ve created an empty method in your release builds. The CheckState() method gets called in all builds, release and debug. It doesn’t do anything in the release builds, but you pay for the method call. You also pay a small cost to load and JIT the empty routine.

  • C#有个越来越好的采用,那正是准则属性。使用规范属性,你能够令你类中的部分方法孤立出来。C# has a better alternative: the Conditional attribute. Using the Conditional attribute, you can isolate functions that should be part of your classes only when a particular environment variable is defined or set to a certain value.
    public string LastName
    {
        get
        { 
            CheckState();
            return lastName;
        }
        set
        {
            CheckState();
            lastName = value;
            CheckState();
        }
    }
    [Conditional("DEBUG")]
    private void CheckState()
    {
    // same code as above
    }
    

    return _lastName;

当第三回试图将LastName属性设置为空字符串或然null时,CheckState将掀起三个预知错误。那样大家就能够纠正set访问器以检讨传递给LastName的参数。那多亏咱们想要的效果。

正确,要创制七个注重于八个景况变量的尺度程序,大家一定要重返使用#if的过时做法中去。可是有着#if都只然则是成立新的标识而已,我们应有制止将可实行代码放在中间。

  • 不管DEBUG遭遇变量是还是不是被定义,CheckState()方法总会被编写翻译且存在于程序聚焦。那也许看上去是没用的,但这只是侵夺一点硬盘空间,CheckState()函数不会被载入到内部存款和储蓄器,更不会被JITed。 Whether the DEBUG environment variable is defined or not, the CheckState() method is compiled and delivered with the assembly. That might seem inefficient, but the only cost is disk space. The CheckState() function does not get loaded into memory and JITed unless it is called.
  • 您也能够创立贰个依赖于愈来愈多情况变量的变量。多规格时是以O路虎极光的样式并列的。下边这些版本的CheckState会在DEBUG只怕TRACE为真时被调用。You can also create methods that depend on more than one environment variable. When you apply multiple conditional attributes, they are combined with OR. For example, this version of CheckState would be called when either DEBUG or TRACE is true

    [Conditional("DEBUG"),
    Conditional("TRACE")]
    private void CheckState()
    
  • 法则属性只好在总体艺术中接收,并且重回值只好是void。The Conditional attribute can be applied only to entire methods

行使了Conditional性情之后,C#编写翻译器唯有在检验到DEBUG意况变量时,才会时有发生对CheckState方法的调用。Conditional本性不会影响CheckState()方法的编写翻译,它只会潜濡默化对该办法的调用。如若定义有DEBUG符号,上面的LastName属性将变为如下的代码:

C#为此提议了大器晚成种更加好的选拔:Conditional性情。使用Conditional个性,大家得以将一些函数隔绝出来,使得它们独有在概念了有些景况变量或然设置了有个别值之后手艺发挥效能。Conditional天性最常用的地点就是将代码改编为调节和测量检验语句。.NET框架已经为此提供了有关的职能接济。上边的代码彰显了Conditional性情的办事原理,以至适用处合。

    CheckState( );

  }

}

    CheckState( );

#endif

    "First Name cannot be null" );

  set

    methodName,

}

要创制贰个运用“与(AND卡塔尔国”关系的布局,大家供给团结在源代码中定义预管理符号:

稍加读者也许对地点代码中的一些库函数还相当不够熟习,大家来总结介绍一下。StackTrace类使用反射(reflection,参见条目43卡塔尔国来获得当前正被调用的点子名。其代价相当的高,但它能够大幅地简化大家的行事,比如扶助我们赢得有关程序流程的新闻。在上边的代码中,使用它,我们便得以收获正被调用的艺术名为CheckState。其他的不二诀要在别的八个类中,分别为System.Diagnostics.Debug和System.Diagnostics.Trace。Debug.Assert方法用于测验有些条件,假诺该法规错误,程序将被甘休,其余参数定义的音信也将被打字与印刷出来。Trace.WriteLine方法规会把确诊音讯打字与印刷到调节和测量检验调整台上。因而,假使有Person对象情状不行,CheckState方法将会呈现音信,并截至程序。大家能够将其视作前置条件和前置条件,在装有的国有方法和受保险方法中调用它。

#if ( VAR1 && VAR2 )

#if/#endif条件编写翻译常用来由相仿份源代码生成分歧的结果文件,最普及的有debug版和release版。不过,那几个工具在切切实实应用中实际不是老大百发百中,因为它们太轻巧被滥用了,使用它们成立的代码平日都相比较难掌握,且难以调节和测验。C#言语的设计者们对这种难题的缓慢解决方案是开创更加好的工具,以达到为分歧条件创设分裂机器码的指标。C#为此增加了二个Conditional脾性,该天性能够标示出某种遭遇设置下有个别方法是不是合宜被调用。使用这种办法来陈诉条件编写翻译要比#if/#endif特别清楚。由于编写翻译器掌握Conditional性情,所以它能够在Conditional天性被选拔时对代码做更好的印证。Conditional本性应用在章程那少年老成档次上,因而它必要我们将标准化代码以艺术为单位来发挥。当要求成立标准代码块时,我们应有接纳Conditional天性来代替古板的#if/#endif。

但在每种公有函数中都做这么的额外检查明显比较浪费时间,大家只怕只愿意其出现在调节和测量试验版本中。那就供给Conditional本性了:

  // 获取正在被调用函数的名目:

  Trace.WriteLine( "Entering CheckState for Person:" );

    new StackTrace( ).GetFrame( 1 ).GetMethod( ).Name;

// 老式的做法:

}

#if DEBUG

  Debug.Assert( _lastName != null,

  }

规格编写翻译#if和#endif使得最终release版本中的CheckState()成为三个空方法,但它在release版和debug版中都将收获调用。纵然在release版中,CheckState()什么也不做,然则大家一定要为方式的加载、JIT编写翻译和调用付出耗费。

[ Conditional( "DEBUG" ) ]

    CheckState( );

Conditional个性只能够运用在全体艺术上。其它索要留意的是,任何一个施用Conditional特性的章程只可以回去void类型。

    CheckState( );

  {

{

    methodName,

  Conditional( "TRACE" ) ]

private void CheckState( )

下边的例子使用了DEBUG可能TRACE那样的预订义符号,但大家也足以将其扩展到大家团结定义的号子上。Conditional性情能够被别的措施定义的标志所主宰,譬喻编写翻译器命令行,操作系统shell的意况变量,大概源代码pragma。

{

大家创造的方法也足以信任于五个情形变量。当大家使用多个Conditional天性时,它们之间的结缘关系将为“或(O昂Cora卡塔 尔(阿拉伯语:قطر‎”。比如,下边包车型客车CheckState方法被调用的标准为定义有DEBUG大概TRACE景况变量:

}

{

不然,将得到如下代码:

  Trace.WriteLine( methodName );

  Trace.WriteLine( "Exiting CheckState for Person" );

  Debug.Assert( _firstName != null,

    methodName,

#endif

private void CheckState( )

任凭是还是不是定义有DEBUG符号,CheckState()方法的方法体都维持不改变,它都会被C#编写翻译器管理,并生成到结果程序聚焦。这一个例子其实也向大家来得了C#编译器的编写翻译进度与JIT编写翻译进程里面包车型地铁界别。这种做法看起来也会拉动或多或少频率损失,可是个中费用的老本唯有是磁盘空间。若无被调用,CheckState()方法并不会加载到内部存款和储蓄器中并拓宽JIT编写翻译。将CheckState()方法生成到程序集中发生的影响是那一个卑不足道的。这种战略成本比不大的属性,换成的却是灵活性。假若感兴趣的话,大家能够查看.NET框架类库中的Debug类来对此赢得更加深的通晓。在各种安装有.NET框架的机械上,System.dll程序聚集都满含有Debug类中负有办法的代码。当调用这一个格局的代码被编写翻译时,系统景况变量将调控这么些方法是还是不是被调用。

    methodName,

  Trace.WriteLine( "Exiting CheckState for Person" );

    CheckState( );

  get

就金科玉律而言,这种做法日常没什么问题,但不时还是也许会在release版本中产生有个别奇特的bug。上面的代码展现了运用#if和#endif条件编写翻译时大概常犯的错误:

    "First Name cannot be null" );

{

  Debug.Assert( _firstName.Length > 0,

    methodName,

private void CheckState( )

营造Person对象时,大家平时会拉长如下的方法来证实目的的不改变式:

  Debug.Assert( _lastName.Length > 0,

 

{

小编们无法在八个办法内的代码块上接受Conditional性子,也不得以在有重回值的艺术上运用Conditional本性。为了利用Conditional特性,大家要求将装有条件性的表现单独置于二个艺术中。固然我们照例须要潜心那些Conditional方法或者给目的情形带给的不好的一面效应,但Conditional特性的割裂政策总归要比#if/#endif好得多。使用#if和#endif代码块,大家很有希望会错误地删除一些首要的措施调用或许赋值语句。

  }

大大多前后相继老鸟都施用过条件编写翻译来检核查象的放松权利条件和前置条件。比方,编写三个私家方法来检查全数类与目的的不变式(invariant卡塔尔国[8],然后将如此的措施开展典型化编写翻译,进而让其只出未来debug版本的次序中。

#if DEBUG

    _lastName = value;

    methodName,

  Console.WriteLine( msg );

    return _lastName;

  Trace.WriteLine( "Entering CheckState for Person" );

}

    CheckState( );

  {

  string methodName =

条款4:使用Conditional特征代替#if规范化编写翻译

    "Last Name cannot be blank" );

  // 获取正在被调用函数的名目:

  {

  set

{

  string msg = null;

public string LastName

  string methodName =

  Debug.Assert( _lastName.Length > 0,

  // 代码保持不改变。

  Debug.Assert( _lastName != null,

    "Last Name cannot be null" );

  Debug.Assert( _firstName != null,

  {

  get

    _lastName = value;

private void CheckState( )

    new StackTrace( ).GetFrame( 1 ).GetMethod( ).Name;

    _lastName = value;

  get

  Trace.Write( "tcalled by " );

#endif

    return _lastName;

    "First Name cannot be blank" );

public string LastName

  }

{

    "Last Name cannot be blank" );

  set

[ Conditional( "DEBUG" ),

  {

    methodName,

  {

public string LastName

#define BOTH

  msg = GetDiagnostics( );

}

条款5:总是提供ToString()方法  34

 

    "First Name cannot be blank" );

  Debug.Assert( _firstName.Length > 0,

public void Func( )

    "Last Name cannot be null" );

总结,使用Conditional性格比选择#if/#endif发生的IL代码更有效能。相同的时候,将其范围在函数等级次序上能够清晰地将条件性的代码分离出来,进而使我们的代码具备越来越好的结构。此外,C#编写翻译器也为此提供了很好的接济,进而扶助我们幸免在此以前使用#if或#endif时常犯的不当。

  }

本文由分分快三计划发布,转载请注明来源

关键词: 分分快三计划 C# C#Effective高 effective c# c#理论拓