Quantcast
Channel: C#タグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 8901

Conditionalメソッドに渡す引数は評価されない

$
0
0

ConditionalAttribute

ログ用関数などによく使うConditionalAttributeという属性クラスがあります。
これは、voidを返すメソッドにつけると、Defineされたシンボル(DEBUGとか)の状態によってそのメソッドの呼び出しを有効にしたり無効にしてくれる属性です。

1
staticvoidMain(string[]args){Log();Console.ReadKey();}[Conditional("LOG")]staticvoidLog(){Console.WriteLine("YukaMaki");}

実行時評価される引数

例えば上記のようにすると、LOGシンボルが定義されているときのみコンソールに文字列が表示されます。では次のようにするとどうなるでしょうか?

2
staticvoidMain(string[]args){Log("Hello World!"+TooHeavy());Console.ReadKey();}[Conditional("LOG")]staticvoidLog(stringmsg){Console.WriteLine(msg);}// 処理に1秒ぐらいかかるとするstaticstringTooHeavy()=>DateTime.Now.ToString();

よく見る光景です。もし、引数はちゃんと評価されているのであれば、本番ビルドでもLogを通るたびに無駄な処理と無駄な文字列のアロケーションがされていることになります。
果たして、引数は評価されているのでしょうか?

3
staticvoidMain(string[]args){Log("Hello World!"+TooHeavy());Console.WriteLine(isCalledHeavy);Console.ReadKey();}[Conditional("LOG")]staticvoidLog(stringmsg){Console.WriteLine(msg);}staticboolisCalledHeavy=false;staticstringTooHeavy(){isCalledHeavy=true;returnDateTime.Now.ToString();}

引数の生成に副作用を持たせてみました。評価されるとisCalledHeavyが立つので評価されたことがわかります。

output
False

結論、引数も評価されなくなりました。無駄な処理も生まれずに安心安心…というわけにはいかず、これは逆に危ないかもしれません。

4
// OKHogeClasshoge=null;boolisSuccess=TryParse(refhoge);Log(isSuccess);// hogeはnullのままだ!!HogeClasshoge=null;Log(TryParse(refhoge));

下のように書いてしまうと、LOGシンボルの有無で全然処理が変わってしまいます。この場合、この後、Null例外が出て「リリースビルドだけばぐってる~~!!😵😵😵」になってしまうでしょう…
この場合は必要な処理が欠ける方ですが、3のソースで、Logの行が長いからと言って、引数をローカル変数に分割した場合には無駄な処理が発生する原因になりえます。

おまけ

stringmsg="Hello World!"+TooHeavy();Log(msg+"_");// 引数を処理させるためにちょいと加工

これをコンパイルしてみます。

IL_0000:ldstr"Hello World!"IL_0005:callstringProgram::TooHeavy()IL_000a:callstring[System.Runtime]System.String::Concat(string,string)IL_000f:popIL_0016:ret

しっかり呼ばれていることが確認できますね。
Conditionalメソッドは、行そのものがなかったことにされています。
TooHeaveyが完全に副作用をもたらさない場合、JITによって消える可能性はある気はします。


Viewing all articles
Browse latest Browse all 8901

Trending Articles