2016-12-14 8 views
38

をカプセル化する場合、私は、このようなコードの部分を持っているを削除しますか?または、評価が維持され、処理時間がかかりますか?C#コンパイラは、それがdebug.writeline

+26

'Debug.WriteLineIf'メソッドを使用します。 –

+4

注:単一のC#コンパイラはありません。いくつかのC#コンパイラがあり、それぞれが多くのバージョンでリリースされています。 C#仕様には(もしあれば)義務的な最適化がほとんどありませんので、特定のコンパイラと特定のバージョンに関してだけ答えが得られます。 –

答えて

47

はい、これは、少なくともDebugの呼び出しであります。 JITコンパイラでもifの評価が削除されても、私はここには見えませんが、等式には副作用がないため、このように思っています。

ただし、評価を削除するためにJITコンパイラに依存しないDebug.WriteLineIfを呼び出すことにより、安全性を保つ方がよい場合があります。

Debug.WriteLineを削除するためのコンパイラの証明を完全にするため。


リリースビルドでコード:デバッグビルドで

.method public hidebysig static void Main(string[] args) cil managed 
{ 
    .entrypoint 
    // Code size  17 (0x11) 
    .maxstack 8 
    IL_0000: call  string [mscorlib]System.Console::ReadLine() 
    IL_0005: ldstr  "Ok" 
    IL_000a: call  bool [mscorlib]System.String::op_Inequality(string, 
                    string) 
    IL_000f: pop 
    IL_0010: ret 
} // end of method Program::Main 

コード:

.method public hidebysig static void Main(string[] args) cil managed 
{ 
    .entrypoint 
    // Code size  42 (0x2a) 
    .maxstack 2 
    .locals init ([0] string state, 
      [1] bool V_1) 
    IL_0000: nop 
    IL_0001: call  string [mscorlib]System.Console::ReadLine() 
    IL_0006: stloc.0 
    IL_0007: ldloc.0 
    IL_0008: ldstr  "Ok" 
    IL_000d: call  bool [mscorlib]System.String::op_Inequality(string, 
                    string) 
    IL_0012: stloc.1 
    IL_0013: ldloc.1 
    IL_0014: brfalse.s IL_0029 
    IL_0016: nop 
    IL_0017: ldstr  "Error occured: {0}" 
    IL_001c: ldloc.0 
    IL_001d: call  string [mscorlib]System.String::Format(string, 
                   object) 
    IL_0022: call  void [System]System.Diagnostics.Debug::WriteLine(string) 
    IL_0027: nop 
    IL_0028: nop 
    IL_0029: ret 
} // end of method Program::Main 

あなたはリリースモードでデバッグモードがないDebug.WriteLineへの呼び出しを、持っていない見たよう

+0

JITがそれを削除していることを確認する方法はありますか? – haim770

+4

私の知る限りではありません。それはブラックボックスです。 –

+0

私は参照してください。ありがとう。いい答え。 – haim770

15

MSDN's page on the Debug class:

からデバッグ情報を印刷し、アサーションを使用してロジックをチェックするDebugクラスのメソッドを使用する場合は、あなたの船積みの製品の性能やコードサイズに影響を与えることなく、あなたのコードをより堅牢にすることができます。

...

ConditionalAttribute属性はDebugの方法に適用されます。 ConditionalAttributeをサポートするコンパイラは、 "DEBUG"が条件付きコンパイルシンボルとして定義されていない限り、これらのメソッドの呼び出しを無視します。

ご覧のとおり、コンパイラは、非デバッグビルドのメンバーDebugへの呼び出しをすべて省略します。ただし、プログラムがif文をチェックするのを止めることはありません。あなたはコンパイラが同様にif文を無視したい場合は、そのようにブロック全体を囲むpreprocessor directiveを使用することができます。

#if DEBUG 
if (state != "Ok") 
{ 
    Debug.WriteLine($"Error occured: {state}, {moreInfo}"); 
} 
#endif 
4

C#コンパイラがDebug呼び出しを削除するために、言語仕様によって必要とされるその議論の評価。

.NET JITが洗練されたJITであった場合、文字列メソッド呼び出しが副作用ではなく、削除できると判断します。 .NET JITはあまり洗練されていないので、実際にはそのメソッドを呼び出す機会があります。確認してみましょう。

デバッガが最適化を抑制することなく、プログラムをリリースモードでコンパイルし、コンパイルして、4.6.2でx64として実行します。これは側 - かもしれないので、私はスペックの許可は、これを最適化するかどうかわからないんだけど

enter image description here

enter image description here

static void Main() 
    { 
     var state = GetState(); 
     if (state != "Ok") 
     { 
      Debug.WriteLine(state); 
     } 
    } 

    [MethodImpl(MethodImplOptions.NoInlining)] 
    static string GetState() 
    { 
     return "x"; 
    } 

C#コンパイラは、完全な文字列の不平等のコールを残しましたエフェクト方法。コンパイラがそのことについてどのように仮定できるかは不明です。

私たちの幻想的なJITも呼び出しを削除しませんでした:

enter image description here

(1)GetState()で、(2)string.!=です。


使用Debug.WriteLineIfので:条件付き属性で飾られた方法は、条件付きメソッドです

17.4.2.1条件付きメソッド 。 Conditional属性は、条件付きコンパイルシンボルをテストして条件を示します。条件付きメソッドへの呼び出しは、このシンボルが呼び出しの時点で定義されているかどうかに応じてインクルードまたは省略されます。シンボルが定義されている場合は、呼び出しが含まれます。それ以外の場合、呼び出し(受信者の評価と呼び出しのパラメーターを含む)は省略されます。

+1

「Debug.X」呼び出しを削除する必要があることを仕様のどこで参照できますか? –

+0

@JeroenVannevel私はそれを追加しました。 – usr