2011-12-15 8 views
2

演算子のオーバーロード、特に暗黙的および明示的な変換では、数値型と予期しない結果を持つ明示的および暗黙的演算子

しかし、私は頻繁に使用されるいくつかの数値パラメータを持っているので、これらのパラメータを強く入力する数値型のラッパーとして構造体を作成しています。ここでの実装例を示します:

public struct Parameter 
{ 
    private Byte _value; 
    public Byte Value { get { return _value; } } 

    public Parameter(Byte value) 
    { 
     _value = value; 
    } 

    // other methods (GetHashCode, Equals, ToString, etc) 

    public static implicit operator Byte(Parameter value) 
    { 
     return value._value; 
    } 
    public static implicit operator Parameter(Byte value) 
    { 
     return new Parameter(value); 
    } 

    public static explicit operator Int16(Parameter value) 
    { 
     return value._value; 
    } 
    public static explicit operator Parameter(Int16 value) 
    { 
     return new Parameter((Byte)value); 
    } 
} 

私は明示的および暗黙の演算子のこつを得るために、私のテスト実装を試してたので、私は明示的に私のParameter型にし、それがスローされませんでした私は驚きにInt64をキャストしてみました例外、さらには驚くべきことに、数字を切り捨てて移動しました。私はカスタムの明示的な演算子を除外しようとし、それは同じように動作しました。

public void TestCast() 
{ 
    try 
    { 
     var i = 12000000146; 
     var p = (Parameter)i; 
     var d = (Double)p; 

     Console.WriteLine(i); //Writes 12000000146 
     Console.WriteLine(p); //Writes 146 
     Console.WriteLine(d); //Writes 146 
    } 
    catch (Exception ex) 
    { 
     Console.WriteLine(ex.Message); //Code not reached 
    } 
} 

は、だから、私は、構造体の代わりにプレーンなByteと私の実験を繰り返し、同じ正確な動作を持っているので、明らかにこれは期待される動作ですが、私は、データの失うことになる明示的なキャストが投げるだろうと思いました例外。

+0

いいえ、明示的なキャストが情報を失うことができます。暗黙的なキャストは行わないでください。 –

+0

'AnyCPU'、' x32'、 'x64'でコンパイルしていますか? – ja72

+0

@ ja72回答が遅れて申し訳ありませんが、x86でコンパイルしています。 – psubsee2003

答えて

7

コンパイラは、明示的内蔵変換の「両側」(または両方)に変換置くために許可されている明示的ユーザ定義変換を分析しています。あなたはフレッドにint型からユーザー定義の変換を持っている、とあなたが持っているのであれば、例えば、:

int? x = whatever; 
Fred f = (Fred)x; 

、コンパイラの理由は、「フレッドにint型からの明示的な変換がありますので、私は明示的に行うことができますintからintへの変換を行い、次にintをFredに変換します。

この例では、longからshortへの明示的な変換が組み込まれており、shortからParameterへのユーザー定義の明示的な変換があります。パラメータをlongに変換することは有効です

暗黙的な変換でも同じことが言えますが、コンパイラは組み込みの暗黙的な変換をeユーザー定義の暗黙的変換の反対側にあります。

ユーザ定義の2つのチェーンをコンパイラが決してチェーンしません。

明示的な変換を正しく作成することは、C#では難しい作業です。変換を扱う仕様の章全体を徹底的に理解するまでは、やめてください。チェーンの変換のいくつかの興味深い側面については

は、件名に私の記事を参照してください。

http://blogs.msdn.com/b/ericlippert/archive/2007/04/16/chained-user-defined-explicit-conversions-in-c.aspx

http://blogs.msdn.com/b/ericlippert/archive/2007/04/18/chained-user-defined-explicit-conversions-in-c-part-two.aspx

+0

あなたのブログへの説明とリンクをありがとう。私は古い投稿のいくつかを見逃してしまったので、これは非常に参考になりました。私が取り組んでいるプロジェクトは、私が実際の仕事で手助けするために使っているように、新しい側面を試してみるために使っているペットプロジェクトのようなものなので、明示的/暗黙的な変換は何でも実験と同じくらいです。 – psubsee2003

+0

あなたのブログを読んだので、私は、明示的および暗黙的なカスタム変換のトラップを理解していると思います。あなたの答えから、私は長いとバイトの間の明示的な変換があることを知っている、コンパイラは、メソッドの呼び出しに長いバイトからパラメータに変換する変換を挿入しています。そして、長からバイトへのキャストは長さから最下位8ビットを取るので、私はパラメータに割り当てられた値として146を残します。完全な意味がある、ありがとう。 – psubsee2003

3

この目標:

ので、私は強く、これらのパラメータ

そして、このコードを入力する数値型のラッパーとしての構造体を作成しています:

public static implicit operator Byte(Parameter value) 
{ 
    return value._value; 
} 
public static implicit operator Parameter(Byte value) 
{ 
    return new Parameter(value); 
} 

がでています全矛盾。 2ウェイの暗黙の演算子を追加することで、ラッパーがもたらす可能性のある型の安全性を取り消すことができます。

暗黙的な変換を削除します。それらを明示的なものに変更することができます。

+0

@ハンク私が探していたタイプセーフティの説明で十分にはっきりしていませんでした。いくつかの異なるタイプのパラメータ(引数のために、Parameter1、Parameter2など)があります。私が探していた型の安全性は、誰かがParameter2を探しているメソッドで誤ってParameter1を使用するのを防ぐことです。しかし、あなたの要点は無関係なので、私は暗黙のオペレータアプローチを再考します。 – psubsee2003

関連する問題