web-dev-qa-db-ja.com

ボックス化解除にC#での明示的なキャストが必要なのはなぜですか?

ボクシングは、値型をマネージヒープオブジェクトに変換するプロセスであり、暗黙的です。ボックス化解除は逆のプロセスであり、コンパイラーは明示的なキャストを必要とします。ボックス化はデータ型を格納するので、ボックス化解除で明示的なキャストを要求する代わりにそれを使用できないのはなぜですか?

class BoxUnBox
{
 static void Main()
 {
   int i = 123;      // a value type
   object o = i;     // boxing
   int j = (int)o;   // unboxing - Why is an explicit cast required?
 }
}
20
RJN

あなたの質問は開封操作だけに関係していません。実際には、「なぜ明示的な変換を使用する必要があるのですか?」次の例を検討してください。

int i = 123;
long l = i;
int j = (int)l; // OMG why??

答えは簡単で、C#仕様で見つけることができます 6.2明示的な変換

明示的な変換とは、常に成功することが証明できない変換情報が失われる可能性があることがわかっている変換、およびドメイン間の変換です。明示的な表記に値するほど十分に異なるタイプの。

上記の例では、longintの範囲に収まらない値を保持できるため、情報を失う可能性があります。ただし、intlongに割り当てるときに情報が失われることはありません。

long l = i; // safe

あなたの例では、暗黙の変換が常に成功することを証明できないため、明示的な変換が必要ですobject型の変数は、文字通り任意の型を参照できます。文字列はどうですか?

object o = i;  // implicit and always safe
o = "Now I have a machinegun ho-ho-ho"; // safe too
int j = o;     // will not succeed if o is string

アナロジー

オブジェクト変数は、音楽CD、ペン、電話、バナナなど、何でも置くことができるブラックボックスのようなものです。あなただけでなく、誰でもそこに何かを置くことができます。朝に最後にブラックボックスに入れたのがバナナだったとしたら、夕方に戻ってブラックボックスから取り出したものを何でも食べられますか?あなたが一人暮らしで、部屋が閉まっていて、あなたの記憶が素晴らしいなら、そして...あなたはそうすることができます。そして、なぜ誰もがそれを食べる前に彼らの箱の内容をチェックするのか不思議に思うでしょう。しかし、あなたが一人で住んでいないか、部屋が閉まっていないか、またはあなたが電話を箱に入れたのを一度だけ忘れることができるなら...食欲をそそる

42

誰かがoの内容を"Hello World"と言うように変更した場合はどうなりますか。何をしているのかを確実に知るために、コンパイラーでは、ボックス化された値を明示的にキャストする必要があります。

基本的に、暗黙的な変換は、オブジェクト型のインスタンスoを、明らかにそうではないintのインスタンスとして表すこともできることを意味します。たとえば、次のことを考慮してください。

int i = -1;
long j = i;

整数である変数ilongと見なすことができることは明らかです。これが、暗黙のキャストがここで正確である理由です。一方、すべてのlongintデータを失うことなくに変換できるわけではありません。したがって、決定するには明示的なキャストが必要です。データが失われる可能性があることはわかっていますが、気にしません。

6
HimBromBeere

Int32isObjectですが、Object多分Int32。コンパイラーは最初のケースで何をすべきかを知っていますが、2番目のケースで何をしているのかをコンパイラーに伝え、ボックス化解除が実行できることを保証する必要があります。

継承関係は方向性があります!親は子供とは異なります。

5
A. Chiesa

すべてのintはオブジェクトに変換可能です。すべてのオブジェクトをintにキャストできるわけではありません。

4

コンパイラは、オブジェクトの内部にあるものを保証できません。そのため、期待する値として明示的にキャストする必要があります。コンパイラーの場合:

これは危険です

object o = 45;
int j = (int)o;

このように:

object o = "something";
int j = (int)o;

そして、それはコンパイル時に許可することはできません。

3
NicoRiff

objectに実際に含まれている内容によっては、実行時にキャストが失敗する場合があります。暗黙の開封が可能な場合は、別の意味の何かを書いた可能性があるため、エラーを見落とす可能性があります(自分または他の人のコードを誤解したかのいずれか)。 本当に欲しいキャストする必要があるため、コンパイラでは明示的にキャストする必要があります。そうしないと、タイプを誤って混合して、エラーが発生しやすいコードを生成する可能性があります。明示的にキャストすることを余儀なくされることによって、あなたは自分のしていることが正しいかどうかを二度考えることを余儀なくされます。

2
Georg Jung

ダイナミックの使用はキャストを回避します

言われたことを損なうことはありませんが、技術的には、開封を実行するためにキャストが必ずしも必要ではないことを指摘したいと思います。 dynamicキーワードを使用すると、システムはボックス化解除と変換を自動的に実行できます。私は動的な使用を推奨も推奨もしていません。単にその動作を指摘しているだけです。

static void DynamicTest()
{
    int i = 123;      // a value type
    object o = i;     // boxing
    dynamic d = o;    // shift to dynamic
    int j = d;        // unboxing - No cast required
}

編集:Jeroen Mostertは、動的キーワードは常にこれを機能させるような魔法ではないことを賢明に指摘しています。評価を実行時の動作に延期するだけです。したがって、上記の例は常に機能しますが、より複雑な例は間違いなく失敗します。したがって、dynamicキーワードを使用するときは注意が必要であり、実行時の失敗を予期(試行/キャッチ)する必要があります。それでも、動的キーワードは、慎重に使用すれば、非常に強力なツールになる可能性があります。

1
Reginald Blue