C#で箱入りの構造体を直接入力するにはどうすればよいですか?

StackOverflow https://stackoverflow.com/questions/3987911

  •  10-10-2019
  •  | 
  •  

質問

私は、さまざまな測定単位(メートル、フィート、インチなど)を表す構造体の名前空間を持っています。

各構造体には暗黙の鋳造演算子が運ばれ、他の測定値型の値を鋳造することをサポートするため、次のサイタックスは合法です。

var oneThousandMeters = new Meters(1000);    
Kilometers aKilo = oneThousandMeters ;     // implicit cast OK. Value = 1 Km

喜びに加えるために、キャッチオールクラスがあります 距離 任意の測定単位を保持することができ、また測定値と測定値を暗黙的に投げかけることができます...

var magnum = new Distance(12, DistanceUnits.Inches); 
Feet wifesDelight = magnum;               // implicit cast OK. Value = 1 foot.

.NETフレームワークの標準に従って、すべての文字列のフォーマットと解析は、IcustomFormatterを実装する外部のフォーマットプロバイダーによって処理されます。悲しいことに、これは、値がフォーマットメソッドに渡されたときにボックス化されていることを意味し、形式の方法は、作用する前にすべての既知の測定タイプに対してオブジェクトをテストする必要があります。内部的には、フォーマットメソッドはとにかく測定値を距離値にキャストするだけなので、ここに質問があります。

質問:

public string Format(string format, object arg, IFormatProvider formatProvider)
{
    Distance distance;           

    // The following line is desired, but fails if arg != typeof(Distance)   
    distance = (Distance)arg;    

    // But the following tedious code works:
    if(arg is Distance)
       distance = (Distance)arg;
    else if(arg is Meters)
       distance = (Distance)(Meters)arg;     // OK. compile uses implicit cast. 
    else if(arg is Feet)
       distance = (Distance)(Feet)arg;       // OK. compile uses implicit cast. 
    else if(arg is Inches)
       distance = (Distance)(Inches)arg;     // OK. compile uses implicit cast. 
    else
        ... // tear you hair out for all 12 measurement types
}

これに対する解決策はありますか、それとも価値タイプの解決できない欠点の1つにすぎませんか?

PS:チェックしました この郵便受け, 、そして質問は似ていますが、それは私が探しているものではありません。

役に立ちましたか?

解決

まあ、それはユーザー定義の変換からボックス化変換を分離することの問題です。両方を発生させたい - そして、ユーザー定義の変換が必要なときにコンパイラに知らせるだけでなく、ボックスを解凍するタイプを指定する必要があります。ユーザー定義の変換を選択する必要があります コンパイル ダイナミックタイピングを使用していない限り時間がかかるため、コンパイラはどのタイプから変換しようとしているかを知る必要があります。

1つのオプションは、を持つことです IDistance インターフェース すべての構造体が実装します。その後、使用することができます:

IDistance distanceArg = arg as IDistance;
if (distanceArg != null)
{
    Distance distance = distanceArg.ToDistance();
}

箱入りの値が既にあるので、インターフェイスを使用すると、余分なボクシングなどが発生しません。各 ToDistance 実装は、おそらく暗黙の変換を使用することができます。

public Distance ToDistance()
{
    return this;
}

...または、変換を使用することができます ToDistance.

他のヒント

ええ、それはあなたが一緒に暮らさなければならないものの1つにすぎません。

整数をオブジェクトに押し込んだ場合、同じことに遭遇します。

int a = 0;
object b = a;
int c = (int)b; // this works
short d = (short)b; // this fails
short e = (short)(int)b; // this works
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top