C#の暗黙的な型変換演算子はいつ使用する必要がありますか?


14

C#では、暗黙的な変換演算子を次のようにオーバーロードできます(MSDNの例):

struct Digit
{
    /* ... */
    public static implicit operator byte(Digit d)  // implicit digit to byte conversion operator
    {
        /* ... */
    }
}

したがって、型(カスタム値型)を使用して、自分自身を別の(無関係な)魔法のように変換し、観客を戸惑わせたままにすることができます(舞台裏を覗き込んで暗黙の変換演算子を見るまで)。

私のコードを読む人を戸惑わせるのは好きではありません。多くの人はそうは思わない。

問題は、コードを理解しにくくすることのない暗黙の型変換演算子のユースケースは何ですか?


1
ワオ。私は実際にこれが存在することを知りませんでした。必ずしも使用するのが良いことではありません。C ++のこの種の機能隠蔽に人々が本当にイライラしていることは知っています。
Katana314

@ Katana314:それは人々が悩むことではありませんでしたが、誰かがオーバーロード(演算子、変換関数、コンストラクター、自由関数またはメンバー関数)を驚くべき動作で追加することについて、できれば微妙に驚くべきことです。
デデュプリケーター

C ++の「演算子のオーバーロード」、特に「キャスト」演算子について読むことをお勧めします。私は、C#が読み物がもっとたくさんある限り議論が3回続いていることを除いて、/に対する同じ議論の多くが同じであると思う。

回答:


18

異なる方法で同じ値を大まかに表す型間の暗黙的な変換のみをお勧めします。例えば:

  • 異なる色の種類が好きRGBHSLHSVCMYK
  • 同じ物理量の異なるユニット(Metervs Inch)。
  • 異なる座標系(極座標vsデカルト座標)。

ただし、暗黙の変換を定義することが適切でない場合を示す強力なガイドラインがいくつかあります。

  • 変換によって精度または範囲が大幅に失われる場合、暗黙的であってはなりません(例:float64からfloat32へ、またはlongからintへ)。
  • 変換が(InvalidCast)例外をスローできる場合、暗黙的ではありません。
  • 変換が実行されるたびにヒープの割り当てが発生する場合、暗黙的ではありません。
  • 変換がO(1)操作でない場合、暗黙的であってはなりません。
  • ソース型またはターゲット型が可変の場合、変換は暗黙的であってはなりません。
  • 変換が何らかの種類のコンテキスト(データベース、カルチャ設定、構成、ファイルシステムなど)に依存している場合、暗黙的であってはなりません(この場合は明示的な変換演算子も推奨しません)。

変換演算子f: T1 -> T2が上記のルールのいずれにも違反していないとすると、次の動作は、変換が暗黙的であることを強く示しています。

  • もしa == b、その後f(a) == f(b)
  • もしa != b、その後f(a) != f(b)
  • もしa.ToString() == b.ToString()、その後f(a).ToString() == f(b).ToString()
  • T1との両方で定義されている他の操作などT2

すべての例は、おそらく損失があります。彼らはとにかく正確な十分なされているかどうか、...
デュプリケータ

ええ、私はそれを実現しました:-)。「損失の多い」というより良い用語は考えられませんでした。「損失の多い」とは、範囲または精度が大幅に低下する変換のことです。例えば、float64からfloat32へ、またはlongからintへ。
エリアンエビング

a!= b => f(a)!= f(b)で、おそらく適用すべきではないと思います。数学の側に、例えば、異なる入力に対して同じ値を返すかもしれない機能がたくさん、床()とはceil()があります
cdkMoose

@cdkMooseもちろんあなたは正しいです。だからこそ、これらのプロパティをルールではなく「ボーナスポイント」として見るのです。2番目のプロパティは、単に変換関数が単射であることを意味します。これは、int32からint64など、厳密に広い範囲を持つ型に変換する場合によくあります。
エリアンエビング

@cdkMoose一方、最初のプロパティは、の同じ等価クラス内の2つの値T1==上の関係によって暗示されるT1)が常にの同じ等価クラス内の2つの値にマップされることを示していますT2。考えてみると、暗黙の変換には実際には最初のプロパティが必要だと思います。
エリアンエビング

6

問題は、コードを理解しにくくすることのない暗黙の型変換演算子のユースケースは何ですか?

(プログラマーと)無関係ではない場合。(コードに関する限り)2つの無関係なタイプがある(まれな)シナリオがあり、実際には(ドメインまたは合理的なプログラマーに関して)関係しています。

たとえば、文字列の照合を行うコード。一般的なシナリオは、文字列リテラルを一致させることです。IsMatch(input, new Literal("some string"))暗黙的な変換では、呼び出すのではなく、その儀式(コード内のノイズ)を取り除き、文字列リテラルに集中できます。

ほとんどのプログラマーはIsMatch(input, "some string")、何が起こっているのかを見てすぐに直観します。これにより、呼び出しサイトでコードが明確になります。つまり、が起こっているのを少し犠牲にして、が起こっているのかを少し理解しやすくします。

さて、同じことをするための単純な関数のオーバーロードの方が良いと主張するかもしれません。そしてそれは。しかし、この種のものが遍在する場合、関数のオーバーロードの山を実行するよりも、1つの変換を持つほうがクリーン(コードが少なく、一貫性が向上)です。

そして、プログラマーが中間タイプを明示的に作成して「実際に何が起こっているのか」を確認するように要求する方が良いと主張するかもしれません。それはそれほど簡単ではありません。個人的には、リテラル文字列の一致の例は、「実際に何が起こっているのか」について非常に明確だと思います。プログラマーはすべてがどのように起こるのメカニズムを知る必要はありません。コードが実行されるさまざまなプロセッサによって、すべてのコードがどのように実行されるかを知っていますか?プログラマが気に停止抽象化のラインは常にありますどのように何かの作品が。暗黙的な変換手順が重要だと思われる場合は、暗黙的な変換を使用しないでください。もし彼らがコンピューターを幸せに保つための単なる儀式だと思うなら、プログラマーはあちこちでそのノイズを見ないほうが良いでしょう、


あなたの最後のポイントをさらに進めることができ、またそうすべきです:それを超えると、プログラマーは何かがどのように行われるかを気にしないほうがましです。
デュプリケータ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.