web-dev-qa-db-ja.com

キャストと変換の違いは何ですか?

この質問 でのEric Lippertのコメントは、私を完全に混乱させました。 C#でのキャストと変換の違いは何ですか?

68
Joel Spolsky

私はエリックが言っていることを信じています:

キャスティングは構文を説明する用語です(つまり、Syntacticの意味です)。

変換は、実際に舞台裏で行われるアクションを説明する用語です(したがって、セマンティックの意味です)。

キャスト式は、式を特定の型に明示的に変換するために使用されます。

そして

(T)E形式のキャスト式(Tは型、Eは単項式)は、Eの値を型Tに明示的に変換(§13.2)します。

構文のキャスト演算子が明示的な変換を実行すると言って、それを裏付けているようです。

45
Justin Niessner

キャストは、コンパイラに「オブジェクトXは実際にはタイプYです。先に進んで、そのように扱う」と伝える方法です。

変換は、「オブジェクトXがタイプYではないことを知っていますが、タイプYのXから新しいオブジェクトを作成する方法が存在します。先に進んで実行してください。」

80
chrissr

リチャードファインマンが哲学の授業に参加していたところ、教授が彼に「ファインマン、あなたは物理学者であり、あなたの意見では電子は「必須のオブジェクト」である」と尋ねた逸話を思い出します。それでファインマンは明確な質問をします「レンガは必須のオブジェクトですか?」クラスに。その質問に対する答えは生徒によって異なります。彼らは、「レンガ」の根本的な抽象的な概念が本質的な目的であると言います。いいえ、1つの特定のユニークなレンガが重要なオブジェクトです。いいえ、経験的に観察できるレンガの部分は重要なオブジェクトです。等々。

もちろん、これはあなたの質問に答えないことです。

これらのダースの答えをすべて調べて、私が本当に何を意味するのかについて著者と議論するつもりはありません。数週間以内にこの件についてブログ記事を書いて、それが問題に光を当てるかどうかを確認します。

例えとして、ラ・ファインマン。あなたは土曜日の朝にバナナブレッドのパンを焼きたいと思っています(私はほとんど毎週土曜日の朝にそうします)。だから、Joy of Cookingに相談すると、「何とか何とか何とか...別のボウルで、乾燥した材料を混ぜ合わせます。 ……」

明らかに、その指示と明日の朝の行動には強い関係がありますが、同様に、指示actionと混同するのは間違いです。指示はテキストで構成されています。特定のページに場所があります。句読点があります。小麦粉と重曹を一緒に泡立てて台所にいて、誰かが「今の句読点は何ですか?」と尋ねたら、おそらく奇妙な質問だと思うでしょう。アクションは命令に関連していますが、命令のテキストプロパティはアクションのプロパティではありません。

キャストは、レシピがケーキを焼く行為ではないのと同じように、変換ではありません。レシピは、実行可能なアクションを説明するテキストです。キャスト演算子は、ランタイムが実行できるアクション(変換)を説明するテキストです。

42
Eric Lippert

C#仕様14.6.6から:

キャスト式は、式を特定の型に明示的に変換するために使用されます。
...
(T)Eという形式のキャスト式(Tは型、Eは単項式)は、Eの値を型Tに明示的に変換(§13.2)します。

したがって、キャストは、明示的な変換を呼び出すようにコンパイラーに指示するために使用される構文構造です。

C#仕様§13から:

変換により、あるタイプの式を別のタイプとして扱うことができます。変換は暗黙的または明示的に行うことができ、これにより明示的なキャストが必要かどうかが決まります。 [例:たとえば、int型からlong型への変換は暗黙的であるため、int型の式は暗黙的にlong型として扱うことができます。 long型からint型への逆の変換は明示的であるため、明示的なキャストが必要です。

したがって、変換は実際の作業が行われる場所です。キャスト式の引用は明示的な変換を実行することを示していますが、明示的な変換は暗黙的な変換のスーパーセットであるため、キャスト式を介して(必要でない場合でも)暗黙的な変換を呼び出すこともできます。

7
Jason Punyon

私の理解だけで、おそらくあまりにも単純すぎる:

重要なデータをキャストするときはそのままです(同じ内部表現)-「これは辞書ですが、ICollectionとして使用できます」。

変換するときは、内部表現を別のものに変更します-「このintを文字列にしたい」。

6
Oded

エリックのコメントを読んだ後、分かりやすい英語での試み:

キャスティングは、2つのタイプが実際にあるレベルで同じであることを意味します。それらは、同じインターフェイスを実装するか、同じ基本クラスから継承するか、ターゲットを「十分に同じ」(スーパーセット?)にして、Int16からInt32へのキャストなどのキャストを機能させることができます。

変換タイプの場合、2つのオブジェクトは変換するのに十分類似している可能性があります。たとえば、数値の文字列表現を考えてみましょう。これは文字列であり、単純に数値にキャストすることはできません。解析して、一方から他方に変換する必要があり、プロセスが失敗する可能性があります。キャストにも失敗する可能性がありますが、それははるかに安価な失敗だと思います。

それが、私が考える2つの概念の主な違いです。変換には、ある種の解析、またはソースデータのより詳細な分析と変換が伴います。キャストは解析しません。それは単に、多態性レベルでの一致を試みます。

5
Paul Sasik

キャスティングは、あるタイプの値を別のタイプの別の値から作成することです。 変換はキャストの一種であり、値の内部表現も(単なる解釈ではなく)変更する必要があります。

C#では、キャストと変換は両方ともcast-expressionで行われます。

typeunary-expression

conversion-operator-declaratorによって変換のみが作成される可能性があるため、区別は重要です(そして、ポイントはコメントで行われます)。したがって、コードでは(暗黙的または明示的な)変換のみを作成できます。

非変換の暗黙的キャストは、サブタイプからスーパータイプへのキャストで常に使用でき、非変換の明示的キャストは、スーパータイプからサブタイプへのキャストで常に使用できます。他の非変換キャストは許可されていません。

2

このコンテキストでは、キャストとは、特定のタイプのオブジェクトを操作のために他のタイプとして公開することを意味し、変換とは、特定のタイプのオブジェクトを実際に別のタイプのオブジェクトに変更することを意味します。

1
heisenberg

キャストは構文であり、変換が含まれる場合と含まれない場合があります(キャストのタイプによって異なります)。ご存じのとおり、C++では キャストのタイプ を指定できます。

階層を上下にキャストすることは、あなたが尋ねた人(および彼らが話している言語!)に応じて、変換と見なされる場合とされない場合があります

Eric(C#)は、別の型へのキャストには常に変換が含まれると述べていますが、その変換によってインスタンスの内部表現が変更されることはありません。

C++の人はstatic_castは余分なコードにならない可能性があります(そのため、「変換」は実際にはありません!)

キャストと変換は基本的にC#と同じ概念ですが、Object.ToString()などのメソッドを使用して変換を行うことができます。キャストは、他の投稿で説明されているキャスト演算子_(T) E_でのみ行われ、変換またはボクシングを利用する場合があります。

どの変換方法を使用していますか?コンパイラーは、コンパイル時にコンパイラーに提供されるクラスとライブラリーに基づいて決定します。暗黙的な変換が存在する場合、キャスト演算子を使用する必要はありません。 _Object o = String.Empty_。明示的な変換のみが存在する場合は、キャスト演算子を使用する必要があります。 String s = (String) o

独自のクラスで createexplicitおよびimplicit変換演算子を使用できます。注:変換を行うと、データが元の型と非常に似たものになったり、まったく見えなくなったりする可能性がありますが、すべて変換メソッドによって定義されており、コンパイラーに合法です。

キャストalwaysは、キャスト演算子の使用を指します。あなたは書ける

_Object o = float.NaN;
String s = (String) o;
_

ただし、s、たとえば_Console.WriteLine_にアクセスすると、ランタイムInvalidCastExceptionを受け取ります。そのため、キャスト演算子は引き続きアクセス時に変換を使用しようとしますが、割り当て中にボクシングを解決します。

0
maxwellb

キャストは、クラス/構造体の演算子です。変換は、影響を受けるクラス/構造体のいずれかに対するメソッド/プロセスであるか、完全に異なるクラス/構造体(つまり、Converter.ToInt32()

キャスト演算子には、暗黙的と明示的な2つの種類があります。

暗黙のキャスト演算子は、あるタイプ(たとえば、Int32)のデータがalwaysを別のタイプ(10進数)として表すことができることを示しますデータ/精度の損失なし

int i = 25;
decimal d = i;

明示的なキャスト演算子は、あるタイプ(10進数)のデータがalwaysを別のタイプ(int)として忠実に表現できることを示しますが、データ/精度が失われる可能性があります。そのため、コンパイラーはexplicitlyを知っている必要があることを明示的にキャスト構文を使用して、とにかくそれを実行することを要求します。

decimal d = 25.0001;
int i = (int)d;

変換では、必ずしも関連があるとは限らない2つのタイプを使用し、解析などのプロセスを介して、一方を他方に変換しようとします。すべての既知の変換アルゴリズムが失敗すると、プロセスは例外をスローするか、デフォルト値を返します。

string s = "200";
int i = Converter.ToInt32(s); // set i to 200 by parsing s

string s = "two hundred";
int i = Converter.ToInt32(s); // sets i to 0 because the parse fails

エリックの構文変換と構文変換の比較は、基本的には演算子と方法論の違いです。

0
Toby

このページ MSDN C#ドキュメントの==は、キャストが変換の特定のインスタンス、つまり「明示的な変換」であることを示唆しています。つまり、x = (int)yという形式の変換はキャストです。

自動データ型変更(myLong = myIntなど)は、より一般的な「変換」です。

0
Dan Puzey