6

アップキャストまたはダウンキャストを行うとき、舞台裏で実際に何が起こりますか?私は次のように何かをするときの考えを持っていました:

string myString = "abc";
object myObject = myString;
string myStringBack = (string)myObject;

最後の行のキャストは、目的がコンパイラーに安全であることを伝えるためだけのものであり、何も悪いことはしていません。そのため、実際にはキャストコードはコード自体に埋め込まれないという考えがありました。私は間違っていたようです:

.maxstack 1
.locals init (
    [0] string myString,
    [1] object myObject,
    [2] string myStringBack)
L_0000: nop 
L_0001: ldstr "abc"
L_0006: stloc.0 
L_0007: ldloc.0 
L_0008: stloc.1 
L_0009: ldloc.1 
L_000a: castclass string
L_000f: stloc.2 
L_0010: ret 

なぜCLRは次のようなものが必要なのcastclass stringですか?

ダウンキャストには2つの可能な実装があります。

  1. が必要ですcastclass something。を実行するコード行に到達するとcastclass、CLRはキャストを作成しようとします。しかし、キャストクラスの文字列行を省略してコードを実行しようとするとどうなるでしょうか。
  2. は必要ありませんcastclass。すべての参照型は同様の内部構造を持っているため、Formインスタンスで文字列を使用しようとすると、誤った使用法の例外がスローされます(Formが文字列またはそのサブタイプではないことを検出するため)。

また、一言で言えば、C#4.0の次の統計は正しいですか?

Upcasting and downcasting between compatible reference types performs reference
conversions: a new reference is created that points to the same object.

それは本当に新しい参照を作成しますか?同じ参照であり、異なるタイプの変数にのみ格納されると思いました。

ありがとう

4

2 に答える 2

13

私は、実際にはキャストコードがコード自体に埋め込まれないという考えを持っていました。

面白いアイデア。これがうまくいくとどう思いましたか?

try
{
    object x = 123;
    object y = (string)x;
}
catch(InvalidCastException ex)
{ ... }

キャストがコードを生成しない場合、例外をスローするコードはどこで発生しますか?

あまり具体的でないタイプからより具体的なタイプへのキャストの主な目的は、ランタイムタイプチェックを実行することであることを忘れないでください。

タイプチェックに合格したら、確かに、他に何もする必要はありません。タイプチェック前の参照ビットとタイプチェック後のビットは同じビットです。ランタイムに、古いビットの新しい使用法が正当化されることを確認させました。

Formインスタンスで文字列を使用しようとすると、誤った使用法の例外がスローされます(Formが文字列またはそのサブタイプではないことを検出するため)。

どこでそれを検出しますか?つまり、正確にどの命令で検出されますか?キャストクラス命令で。それがcastclass命令の目的です。

キャストクラスの文字列行を省略してコードを実行しようとするとどうなりますか?

タイプセーフティベリファイアはあなたのプログラムを拒否したでしょう。検証に合格せずにCLRに強制的に実行させた場合、未定義の動作が発生します。成功したか、失敗したか、ハードディスクをフォーマットした可能性があります。

それは本当に新しい参照を作成しますか?

実装レベルでは、参照は単なるポインタサイズの整数であることを忘れないでください。これは、メモリマネージャが参照されるデータの位置を追跡するために使用できる数値です。それはポインタかもしれませんし、ハンドルかもしれません。それが何であるかは関係ありません。これは、参照の抽象的な概念を実装するものです。

12を含む変数があり、その内容を12に「置き換える」場合、それは作成されたばかりの「新しい」12ですか、それとも「古い」12ですか。2番目の変数を作成し、最初の変数からコピーして12を入力するとします。それは「新しい」12ですか、それとも「古い」12ですか。どうやってわかりますか?違いはありません。「古い」参照と同じ「新しい」参照を作成する場合、それは何か新しいものを作成することですか?質問は哲学的な質問であり、技術的な質問ではありません。

于 2010-05-06T23:00:00.937 に答える
5

参照とインスタンスを混同しています。新しいインスタンスではなく、新しい参照が作成されます。

object foo = "bar";
string baz = (string)foo;

文字列への新しい参照"foo"が変数に割り当てられbazます(ただし、文字列のインスタンスは1つだけで、両方の変数が1つのインスタンスを指しているだけです)。そうでない場合は、「ハンドル」タイプに似たものがあります。bazfooが文字通り同じ参照である場合、これ。

foo = "bim";

また、bazequalになり"bim"ます(同様に、非文字列型を割り当てるbazと、有効な文字列参照をポイントしなくなります)。

参照型が同じ継承階層にある場合(一方が他方から直接または間接的に継承する場合)、または型間に明示的な変換が存在する場合に、参照型に対してキャストを実行できます。他のすべての演算子と同様に、明示的な変換はポリモーフィックではないことに注意してください。つまり、変換は、階層内の別のポイントではなく、問題のクラスの1つで具体的に定義する必要があります。

明示的な変換が存在する場合、それがなくても問題のタイプに互換性がある場合でも、明示的な変換が優先されます。明示的な変換の場合、キャスト/変換の結果がキャストされているオブジェクトと同じインスタンスを指すという保証はありません(実際、ほとんどありません)。

于 2010-05-06T18:44:21.610 に答える