どういうわけか同等と思われるかもしれませんが、目的はまったく異なります。まず、キャストとは何かを定義してみましょう。
キャストとは、あるデータ型のエンティティを別のデータ型に変更するアクションです。
これは少し一般的で、キャストは変換の構文が同じであることが多いため、変換と何らかの形で同等です。そのため、言語でキャスト(暗黙的または明示的)がいつ許可され、いつ((詳細)明示的な変換?
まず、それらの間に簡単な線を引きます。正式には(言語構文と同等であっても)キャストはタイプを変更しますが、変換は値を変更します/変更する可能性があります(最終的にはタイプと一緒に)。また、キャストはリバーシブルですが、変換はリバーシブルではない場合があります。
このトピックはかなり広大なので、カスタムキャスト演算子をゲームから除外して少し絞り込んでみましょう。
暗黙のキャスト
C#では、情報が失われない場合、キャストは暗黙的です(このチェックは、実際の値ではなく型を使用して実行されることに注意してください)。
プリミティブ型
例えば:
int tinyInteger = 10;
long bigInteger = tinyInteger;
float tinyReal = 10.0f;
double bigReal = tinyReal;
変換中に情報が失われることはないため、これらのキャストは暗黙的です(タイプを広くするだけです)。逆に暗黙的なキャストは許可されていません。これは、実際の値に関係なく(実行時にのみチェックできるため)、変換中に一部の情報が失われる可能性があるためです。たとえば、このコードはコンパイルされません。double
これは、にfloat
:で表現できない値が含まれている可能性があるためです(実際にはコンパイルされます)。
double bigReal = Double.MaxValue;
float tinyReal = bigReal;
オブジェクト
オブジェクト(へのポインタ)の場合、コンパイラがソースタイプが派生クラスである(または実装する)ことを確認できる場合、キャストは常に暗黙的です。次に例を示します。
string text = "123";
IFormattable formattable = text;
NotSupportedException derivedException = new NotSupportedException();
Exception baseException = derivedException;
この場合、コンパイラはそれが実装されていることを認識しており、それは(から派生している)ので、キャストは暗黙的です。オブジェクトはタイプを変更しないため、情報が失われることはありません(これは、キャストを使用して別のタイプの新しいオブジェクトを作成するため、sおよびプリミティブタイプとは異なります)。変更されるのは、オブジェクトのビューです。string
IFormattable
NotSupportedException
Exception
struct
明示的なキャスト
変換がコンパイラーによって暗黙的に行われない場合、キャストは明示的であり、キャスト演算子を使用する必要があります。通常、それは次のことを意味します。
- 情報やデータが失われる可能性があるため、注意する必要があります。
- 変換が失敗する可能性があるため(一方のタイプをもう一方のタイプに変換できないため)、繰り返しになりますが、何をしているのかを知っておく必要があります。
プリミティブ型
変換中に一部のデータが失われる可能性がある場合、プリミティブ型には明示的なキャストが必要です。次に例を示します。
double precise = Math.Cos(Math.PI * 1.23456) / Math.Sin(1.23456);
float coarse = (float)precise;
float epsilon = (float)Double.Epsilon;
どちらの例でも、値が範囲内にある場合でも、float
情報(この場合は精度)が失われるため、変換は明示的である必要があります。今これを試してください:
float max = (float)Double.MaxValue;
この変換は失敗するので、繰り返しになりますが、明示的である必要があるため、それを認識してチェックを行うことができます(この例では、値は一定ですが、実行時の計算またはI / Oから取得される場合があります)。あなたの例に戻る:
string text = "123";
double value = (double)text;
コンパイラはテキストを数値に変換できないため、これはコンパイルされません。テキストには、数字だけでなく任意の文字を含めることができます。これは、C#では、明示的なキャストの場合でも多すぎます(ただし、別の言語では許可される場合があります)。
オブジェクト
型が関連していない場合、ポインタから(オブジェクトへの)変換が失敗する可能性があります。たとえば、このコードはコンパイルされません(コンパイラは可能な変換がないことを認識しているため)。
string text = (string)AppDomain.Current;
Exception exception = (Exception)"abc";
このコードはコンパイルされますが、実行時に失敗する可能性があります(キャストされたオブジェクトの有効なタイプによって異なります)InvalidCastException
。
object obj = GetNextObjectFromInput();
string text = (string)obj;
obj = GetNextObjectFromInput();
Exception exception = (Exception)obj;
変換
それで、最後に、キャストが変換である場合、なぜ私たちはのようなクラスが必要なのConvert
ですか?キャストを使用したC#ではコンパイラに次のように言うため、実際にはConvert
実装とIConvertible
実装に起因する微妙な違いを無視します。
私を信じてください、このタイプはあなたが今それを知ることができなくてもそのタイプです、私にそれをさせてください、そしてあなたは見るでしょう。
-または-
心配しないでください。この変換で何かが失われるかどうかは気にしません。
それ以外の場合は、より明示的な操作が必要です(簡単なキャストの影響について考えてください。そのため、C ++では長く冗長で明示的な構文が導入されました)。これには複雑な操作が含まれる場合があります(string
->double
変換の場合は解析が必要になります)。string
たとえば、への変換は(ToString()
メソッドを介して)常に可能ですが、期待するものとは異なる意味を持つ可能性があるため、キャストよりも明示的である必要があります(書くほど、自分がしていることについて考えるようになります)。
この変換は、カスタム変換演算子(キャストするクラスで定義)またはより複雑なメカニズム(TypeConverter
たとえば、sまたはクラスメソッド)を使用して、オブジェクト内で(そのための既知のIL命令を使用して)実行できます。何が起こるかはわかりませんが、失敗する可能性があることはわかっています(そのため、より制御された変換が可能な場合はIMOを使用する必要があります)。あなたの場合、変換は単にを解析しstring
てdouble
:を生成します。
double value = Double.Parse(aStringVariable);
もちろん、これは失敗する可能性があるため、これを行う場合は、スローされる可能性のある例外を常にキャッチする必要があります(FormatException
)。ここではトピックから外れていますが、aTryParse
が使用可能な場合は、それを使用する必要があります(意味的には、数値ではない可能性があり、失敗するのがさらに速いためです)。
.NETでの変換はTypeConverter
、ユーザー定義の変換演算子を使用した暗黙的/明示的なキャスト、IConvertible
メソッドの実装と解析など、さまざまな場所から発生する可能性があります(何かを忘れましたか?)。それらの詳細については、MSDNを参照してください。
この長い答えを終えるために、ユーザー定義の変換演算子についてほんの少しだけ説明します。プログラマーがキャストを使用して、あるタイプを別のタイプに変換できるようにするのは、単なる砂糖です。これは、クラス(キャストされるもの)内のメソッドであり、「ねえ、彼/彼女がこの型をその型に変換したいのなら、私はそれを行うことができます」と言います。例えば:
float? maybe = 10;
float sure1 = (float)maybe;
float sure2 = maybe.Value;
この場合、失敗する可能性があるため明示的ですが、これは実装に委ねられます(これに関するガイドラインがある場合でも)。次のようなカスタム文字列クラスを作成するとします。
EasyString text = "123";
double value = (string)text;
あなたの実装では、「プログラマーの生活を楽にする」ことを決定し、キャストを介してこの変換を公開することを決定できます(これは書き込みを減らすための単なるショートカットであることを忘れないでください)。一部の言語ではこれが許可される場合もあります。
double value = "123";
任意のタイプへの暗黙的な変換を許可します(チェックは実行時に行われます)。適切なオプションを使用すると、これは、たとえばVB.NETで実行できます。それはただ異なる哲学です。
私はそれらで何ができますか?
したがって、最後の質問は、いつどちらを使用するかです。明示的なキャストをいつ使用できるか見てみましょう。
- 基本タイプ間の変換。
- から
object
他のタイプへの変換(これには開封も含まれる場合があります)。
- 派生クラスから基本クラス(または実装されたインターフェース)への変換。
- カスタム変換演算子を使用した、あるタイプから別のタイプへの変換。
最初の変換のみを実行できるConvert
ため、他の変換は選択の余地がなく、明示的なキャストを使用する必要があります。
いつ使用できるか見てみましょうConvert
:
- 任意の基本タイプから別の基本タイプへの変換(いくつかの制限があります。MSDNを参照してください)。
- 実装
IConvertible
する任意のタイプから他の(サポートされている)タイプへの変換。
byte
配列と文字列との間の変換。
結論
IMOConvert
は、キャストで同じ変換を実行できる場合でも(他に何かが利用可能でない限り)、変換が失敗する可能性があることがわかっている場合は常に使用する必要があります(形式、範囲、またはサポートされていない可能性があるため)。誰があなたのコードを読むのか、あなたの意図は何か、そしてそれが失敗するかもしれないことを明らかにします(デバッグを簡素化します)。
他のすべてについてはキャストを使用する必要があり、選択の余地はありませんが、別のより良い方法が利用できる場合は、それを使用することをお勧めします。あなたの例では、からstring
への変換double
は(特にテキストがユーザーからのものである場合)非常に頻繁に失敗するものであるため、たとえばTryParse
メソッドを使用して、可能な限り明示的にする必要があります(さらに制御を強化する必要があります)。
編集:それらの違いは何ですか?
更新された質問と私が以前に書いたことを維持すること(使用できる/使用する必要があるときと比較してキャストを使用できるときについてConvert
)によると、明確にする最後のポイントは、それらの間に違いがあるかどうかです(さらに、操作を実行できるようにConvert
使用IConvertible
とIFormattable
インターフェイスキャストでは許可されていません)。
簡単な答えは「はい」です。動作が異なります。このConvert
クラスはヘルパーメソッドクラスのように見えるので、多くの場合、何らかの利点やわずかに異なる動作を提供します。例えば:
double real = 1.6;
int castedInteger = (int)real;
int convertedInteger = Convert.ToInt32(real);
かなり違いますよね?キャストは切り捨てられますが(これは私たち全員が期待することです)、Convert
最も近い整数への丸めを実行します(これは、知らない場合は予期されない可能性があります)。それぞれの変換方法には違いがあるため、一般的なルールを適用することはできず、ケースバイケースで確認する必要があります...他のすべてのタイプに変換するには19の基本タイプ...リストはかなり長くなる可能性があり、MSDNのケースバイを参照する方がはるかに優れています場合!