VB.NETでも3項演算子を使いたい
はじめに
最近はVBでもPythonみたいに関数内に関数を定義できねーかなぁと考えている弊社です。
あと、出来ればVBでもカリー化関数を扱いたい。 もっとカジュアルに関数を扱いたいのでMicrosoftさんオナシャス。
とまぁ、儚い夢を願ったところで本題です。 VBには3項演算子*1と3項演算子っぽい何かがあるのは生産性アプリケーションを書いている皆さんには常識的な事だと思います。
旧来からある(らしい)IIf
関数と割と新顔(らしい)*2If
演算子の二つです。
まぁ、関数ってある時点で色々と察しがつくのですが、とりあえずmsdnを見てみましょう。
If 演算子 (Visual Basic) | Microsoft Docs
If
とIIf
の違いは上のリンク内に書いてあるので使い方の説明は割愛します。
Let's IL
Dim result = IIf(True, a(), b())
IIf
の実態はMicrosoft.VisualBasic.Interaction
に属する3項演算子っぽい働きをする関数です。
よって関数の呼び出し前に3つの式が評価されてからIIf
が呼ばれます。
.maxstack 3 .locals init ([0] object result) IL_0000: nop IL_0001: ldc.i4.1 IL_0002: call int32 SectionOperator.Module1::a() IL_0007: box [mscorlib]System.Int32 IL_000c: call int32 SectionOperator.Module1::b() IL_0011: box [mscorlib]System.Int32 IL_0016: call object [Microsoft.VisualBasic]Microsoft.VisualBasic.Interaction::IIf(bool, object, object) IL_001b: call object [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::GetObjectValue(object) IL_0020: stloc.0 IL_0021: nop IL_0022: ret
result
にはa()
の返り値が格納されますが、IIf
呼び出し前にa()
とb()
の両方が呼び出さています。
なのでa()
やb()
などに副作用がある場合は予想に反する動きをして戸惑うかもしれません。
また、IIf
は返り値がIIf(bool, object, object) -> object
なのでOption Strict On
とはキャストのオンパレードとなり相性が悪いと思います。
Dim result = If(True, a(), b())
.maxstack 1 .locals init ([0] int32 result) IL_0000: nop IL_0001: ldc.i4.1 IL_0002: brtrue.s IL_000b IL_0004: call int32 SectionOperator.Module1::b() IL_0009: br.s IL_0010 IL_000b: call int32 SectionOperator.Module1::a() IL_0010: stloc.0 IL_0011: nop IL_0012: ret
If
演算子では条件によってどちらか一方しか評価されません。
また、IIf
のように明示的にキャストする必要もないのでこちらの方が便利ですね。
まとめ
以上のことから今のご時世IIf
を使うメリットはほぼ無いと思います。
むしろIIf
を使い必ず副作用を発生させないといけないような設計をしている場合は今すぐ改めるべきです。
おわり