タイトルの通り黒魔術です(多分)、実行環境ごとの動作はどうなるかわかりません。
また、C#などの仕様変更で使い物にならなくなる可能性はあります。(Support extension methods everywhereの流れ次第では仕様変更が入るかもしれない)
implicit operatorとはなんぞや
C#では比較演算子などのオーバーロードができます。その中(?)にimplicit operatorやexplicit operatorがあります。こいつらは暗黙的なキャストと明示的なキャストをオーバーロードすることができます。
たとえばこんなコード↓があったとして
こんなコード↓は合法(コンパイル&実行可能)です
explicit operatorなら明示的なキャストが必要でになります。
また、implicit/explicit operatorは変換元のクラス/構造体以外に変換先のクラス/構造体にも定義することができて、以下のコードも合法です。
現時点(C# 7.3)ではimplicit/explicit operatorが定義できる場所は2箇所ということになります。
implicit operator 2箇所で定義したらどうなる?
当然生まれる疑問です。
以下のコードに関しては合法です。
ただし、以下のコードに関してはコンパイルエラー
まぁ、当たり前っちゃ当たり前です。どちらのimplicit operatorを実行すればいいかわからないのだから。
黒魔術
ちょっと必要性があって式ツリーでキャストするコードを描いていた時に気づいてしまいました。
こんな感じでラムダを動的生成してやり、以下のようなコードを書いてしまうと:
コンパイル時のチェックはもちろんできないのでコンパイルできてしまいます。
また、実行してやると:
が出力されるので、見事「あいまいなユーザー定義の変換」を回避できてしまいました。explicit operatorの場合も同じ挙動です。
かなり、興味深い内容ですね。
implicit operatorは内部的にはop_Implicit
という名のstatic special name メソッドになります。
リフレクションで取ってくるときはMethodInfo.IsSpecialName
がtrueになるメソッドです。
変換元のop_Implicit
メソッドを優先的に叩いたという感じでしょうか?
何はともあれ、こんな非合法すれっすれのimplicit/explicit operatorがあるコードが実際に飛んでくることはないとおもうので、式ツリーでキャストするときはimplicit/explicit operatorの数なんか気にせずやればいいと思います。
重要なことですが最後に、implicit operatorは容量用法を守って適切に使いましょう。多用は厳禁です。