myFoo = myFoo ?? new Foo();
の代わりに
if (myFoo == null) myFoo = new Foo();
コードの最初の行が常に代入を実行すると思いますか?また、これはヌル合体演算子の悪い使用ですか?
myFoo = myFoo ?? new Foo();
の代わりに
if (myFoo == null) myFoo = new Foo();
コードの最初の行が常に代入を実行すると思いますか?また、これはヌル合体演算子の悪い使用ですか?
私は、生成されたコードのCILを比較しました(csc.exe
の/optimize
スイッチに対応するプロジェクトのプロパティでリリースビルド - コードの最適化を確認してください)を比較しました。これは私が(VS 2008を使用して - 時々Foo
、Foo.MaybeFoo()
は時々null
を返すメソッドであることに注意してください)得たものである
GetFooWithIf
:
IL_0000: call class Application3.Foo Application3.Foo::MaybeFoo()
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: brtrue.s IL_000f
IL_0009: newobj instance void Application3.Foo::.ctor()
IL_000e: stloc.0
IL_000f: ldloc.0
IL_0010: ret
GetFooWithCoalescingOperator
:
IL_0000: call class Application3.Foo Application3.Foo::MaybeFoo()
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: dup
IL_0008: brtrue.s IL_0010
IL_000a: pop
IL_000b: newobj instance void Application3.Foo::.ctor()
IL_0010: stloc.0
IL_0011: ldloc.0
IL_0012: ret
このように、余分なトップ・オブ・スタックの複製とポップを除いて同じです。測定可能な性能差を作るためにこれを行うことができれば、私はそれを食べる目的で特に帽子を購入するでしょう。したがって、読みやすさが向上していると感じるものと一緒に行ってください。
(編集)ああ、JITterは、その違いをなくすには十分に賢いかもしれない!
最初の行が常に割り当てを行うという点では正しいです。コードが非常に頻繁に実行されない限り、私は心配しません。
コンパイラが最適化をやめないようにするには? – Timbo
@Timbo:私はコンパイラがどのような最適化をしているのか、そうしていないのかよく知っているわけではありませんが、私は 'myFoo'がコードのどこかで使用され、コンパイラが最適化できないことを前提にしています。他の場所で使用されていない場合は、別の話です。 –
私はこれをヌル合体演算子の悪い使用とは考えていません。コードを読むとき、できるだけ簡潔で簡潔であり、コードの意図は明らかです。
このようにヌル合体演算子を使用すると、常に代入が行われますが、それについては心配しません。 (の場合、実際にはがパフォーマンスの問題であることが判明しています。
'?? ='演算子の説得力のある引数を作る: –
この場合、@PavelMinaevは '|| ='演算子と同じではないのですか?それ自身の演算子を保証するために 'if(!isset(myFoo))myFoo = new Foo();'の呼び出しを置き換える必要があります。 –
'||'はブール値を必要とするので、同じではありません。 –