C#にはVB.NETのDirectCastと同等のものがありますか?
()キャストと 'as'キーワードがありますが、CTypeとTryCastに対応していることは承知しています。
明確にするために、これらのキーワードは次のことを行います。
CType /()casts:既に正しい型である場合はキャストします。そうでない場合は、型コンバーターを探して呼び出します。型コンバーターが見つからない場合は、InvalidCastExceptionをスローします。
TryCast/"as"キーワード:正しい型であればキャストし、そうでなければnullを返します。
DirectCast:正しい型の場合はキャストし、そうでない場合はInvalidCastExceptionをスローします。
上記を詳しく説明した後、一部の人々はまだ()は同等であると答えているので、なぜそうでないのかをさらに詳しく説明します。
DirectCastでは、継承ツリーでの変換の縮小または拡大のみが許可されます。 ()のような異なるブランチ間での変換はサポートしていません。
C#-これはコンパイルして実行します:
//This code uses a type converter to go across an inheritance tree
double d = 10;
int i = (int)d;
VB.NET-これはコンパイルしません
'Direct cast can only go up or down a branch, never across to a different one.
Dim d As Double = 10
Dim i As Integer = DirectCast(d, Integer)
VB.NETで私のC#コードに相当するものはCTypeです。
'This compiles and runs
Dim d As Double = 10
Dim i As Integer = CType(d, Integer)
必要な機能がC#にないことは明らかです。これを試してみてください...
static T DirectCast<T>(object o, Type type) where T : class
{
if (!(type.IsInstanceOfType(o)))
{
throw new ArgumentException();
}
T value = o as T;
if (value == null && o != null)
{
throw new InvalidCastException();
}
return value;
}
または、VBとは異なりますが、次のように呼び出します。
static T DirectCast<T>(object o) where T : class
{
T value = o as T;
if (value == null && o != null)
{
throw new InvalidCastException();
}
return value;
}
2回目の更新:
OK、これは基本的にVB.NETでDirectCast
が行うことを基本的に行うと提案されているC#メソッドです。
static T DirectCast<T>(object o) where T : class
{
T value = o as T;
if (value == null && o != null)
{
throw new InvalidCastException();
}
return value;
}
上記の方法の問題は次のとおりです:
where T : class
制約があり、DirectCast
にはありません。System.Object
として囲みます-繰り返しますが、DirectCast
には当てはまりません(少なくとも私が知っていることではありません)。as
を不必要に使用します(そのため、最初にclass
制約があります)。 (T)oを呼び出すと、機能しない場合はInvalidCastException
がスローされます。 as
を使用して値が一致するかどうかを確認し、最初に(T)o
ルートを行った場合にスローされるのと同じ例外をスローするだけですか?メソッドは、次のようにDirectCast
と同じ結果を提供するように実際に書き換えることができます。
static T DirectCast<T>(object o) {
return (T)o;
}
おもしろい観察:このメソッドが実際に行っているのは、値をボックス化してから、そのボックス化を解除することです。言い換えれば、DirectCast<int>(12.0)
は実際には(int)(object)12.0
と同じです(そしてどちらも例外をスローします)。これを実現すると、提案されているDirectCast<T>
メソッドはまったく不要になります。
ここで、DirectCast
と()
を使用したキャストがVB.NETとC#でどのように「異なる」かの例を示します。
VB:
Dim i As Integer = 12
Dim l As Long = DirectCast(i, Long) ' does not compile '
C#:
int i = 12;
long l = i; // DOES compile
よし、一方はコンパイルし、もう一方はコンパイルしません。しかし、そのコードを見てください。 オブジェクトの型を既に知っている場合のDirectCast
のポイントは何ですか?これは現実的な比較ではありません。VB.NETでは、上記のコードのようにDirectCast
を呼び出す理由はないからです。 (VB.NETで値_タイプSystem.Int32
であることがわかっている値をタイプSystem.Int64
の値に変換する場合は、CLng
ではなくDirectCast
を使用します。)そこにSystem.Object
と入力された変数がある場合、 thenDirectCast
を使用することは理にかなっており、以下のコードは実際に同等です:
VB:
Dim i As Integer = 12
Dim o As Object = i
Dim l As Long = DirectCast(o, Long) ' compiles, throws an exception '
C#:
int i = 12;
object o = i;
long l = (long)o; // compiles, throws an exception
したがって、VB.NETでは、DirectCast
を、実際に使用することが理にかなっているシナリオ(つまり、コンパイル時にオブジェクトの型がわからない場合)で、まっすぐな()
と同じ-style cast in C#。
[〜#〜] edit [〜#〜]:さて、いくつかのVBコンパイルできなかったコードを投稿したことを恥ずかしく思います。 、私はsecondanswerを撤回しますが、最初を維持します。
DirectCast
の使用法を参照している場合、不明な型のオブジェクトを取得して目的の型にキャストしようとすると、isとC#の()キャストと同じです:
VB:
Dim o As Object = SomeObject()
Dim i As Integer = DirectCast(o, Integer)
C#:
object o = SomeObject();
int i = (int)o;
これは、o
がSystem.Object
として入力された場合、C#の()
操作がボックス化を解除しようとするためです。タイプが正確に一致しない場合、これは失敗します。たとえば、o
がボックス化されたSystem.Double
である場合、o
mustが(int)o
に変換される前にSystem.Double
としてアンボックス化されるため、System.Int32
は例外をスローします(信じられない場合は試してください自分のために!)。
注:以下は、DirectCast
がnot拡大変換を実行するため不正確です;いずれにしても、私はそれを後世に残しています。
一方、拡大変換と縮小変換を扱う場合、C#で()
操作を使用すると、先ほど指摘したように単純なキャストよりも多くの作業が行われます(つまり、(int)someDouble
を実行できます)。このシナリオでは、DirectCast
はC#の単純な古い割り当てと同等です。
VB:
Dim i As Integer = 12
Dim l As Long = DirectCast(i, Long) ' does not compile, actually '
C#:
int i = 12;
long l = i;
実際、コンパイラは、型付き変数を他の型に変換できないと推測した場合、DirectCast違反をキャッチします。
これらは実際の同等物です:
double d = 10;
int i = (int)d;
Dim d As Double = 10
Dim i As Integer = d
この構造の危険性に注意してください。VB.NETで単にdoubleを整数に割り当てるだけでは、誤ってdoubleが整数に縮小されます。
一方、C#プログラマーは、変数.NETを誤ってダウンサイズしないというコンパイル時の安全性を享受します。 VB.NETプログラマーは、常にDirectCastを安全なプログラミング習慣として置くことに取り組まなければなりません
これらは実際の同等物です:
// will not compile, cannot convert double to int
double d = 10;
int i = d;
' will not compile, cannot convert double to int
Dim d As Double = 10
Dim i As Integer = DirectCast(d, Integer)
[編集]
@ダンタオ:
C#でDirectCastを使用する必要はありません。ランタイムは、longから整数への値の読み込みも防ぎます。これはcsauveが競合していることです。C#にはDirectCastがありません。DirectCastはさまざまなタイプの変数の割り当てを防ぐことができますが、C#にはこのDirectCastがないためしかし、ご覧のとおり、C#のキャストはexactly DirectCastと同じです。これにより、InvalidCastExceptionランタイムエラーが発生します。
long l = 10;
object o = l;
int i = (int)o;
これにより、上記と同じランタイムエラーも発生します。
Dim l As Long = 10
Dim o As Object = l
Dim i As Integer = DirectCast(o, Integer)
さて、ここが「楽しい」部分の出番です。VB.NETでは、何かを達成するために多くのキーワードを覚えておく必要があります。 C#では、特定のキーワードが別のシナリオ(この変数のダウンキャストなど)で使用できる場合、それを実現するためだけに別のキーワードを発明しません。
C#では、これを行うだけです。
long l = 10;
object o = l;
int i = (int)(long)o;
VB.NETでは、変数を本当にダウンキャストしたい場合、それを行うための直交的な方法が必要な場合、つまり1つのキーワードを覚えているだけであれば、これを行う必要があります:
Dim l As Long = 10
Dim o As Object = l
Dim i As Integer = DirectCast(DirectCast(o, Long), Integer)
しかし、それはコンパイルされませんので、整数へのロングキャストをどのように達成するのですか? VB.NETの他のキーワードを覚えておく必要があります。 C#では直交ですが、この構造を使用して変数のボックス化を解除します(typehere)
、同じコンストラクトを使用してダウンキャスト/アップキャストします(typehere)
。 VB.NETでは、オブジェクトから値をロードすることとダウンキャストすることとの間に根本的な切断があります。 VB.NETでは、これを行う必要があります。
Dim l As Long = 10
Dim o As Object = l
Dim i As Integer = CType(o, Integer)
うーん。csauveの混乱は、C#が(typehere)
、最初にダウンキャストに使用されます。第二に、同じコンストラクト(この投稿の最初の部分、object o = l
)は、オブジェクトからの値のボックス化解除にも使用されます。DirectCastの安全な型変換動作が保証されているため、これらは同じです。
このダウンキャスト...
long l = 1;
int i = (int) l;
...は次のものと同等ではありません:
Dim l As Long = 1
Dim i As Integer = DirectCast(l, Integer)
ダウンキャスティングを実行する場合、これを行う必要があります。
Dim l As Long = 1
Dim i As Integer = CInt(l) ' can also use CType
VB.NETプログラマーが意図的にプログラミングし、コーディング中に眠くない場合、異なるタイプを割り当てることができないことを完全に認識しているときにDirectCastを使用するのはなぜですか? VB.NETプログラマーが本当に望んでいたものがダウンキャストである場合、そもそもDirectCastを試してはいけません。 VB.NETプログラマーは、DirectCastをダウンキャストに使用できないことを発見すると、作成したものをバックスペースし、CInt(またはCType)に置き換える必要があります。
自分で実装できます:
static T CastTo<T>(this object obj) { return (T)obj; }
次のように使用できます。
3.5.CastTo<int>(); //throws InvalidCastException.
ジェネリックは実行時に「解決」されるが、型変換はコンパイル時に解決されるため、これは機能し、ユーザー定義のコンバーターは関与しません。フレームワークは、各T
に対して個別の実装を実際に生成しませんむしろ同様のT
の実装を共有しているため、ランタイムにはカスタム変換を解決するための情報がありません。
VB.NET:
Dim xxx as label = Directcast(sender, label)
C#:
label xxx = (label)sender;
DirectCast
および()
は常に同じILを生成するとは限らないため、これはVBとC#コンパイラの違いだと思います。
AFAICT、参照型はcastclass
IL命令を使用してキャストされますが、値型の場合、コンパイラは入力型に応じて関連するILを生成します。
C#では、double
からinteger
にキャストするとconv.i4
IL命令。これは、値が大きすぎる場合に出力の符号ビットなどを陽気に上書きします。 VBでは、コンパイルエラーです。
興味深いことに、中間のobject
変数を使用してdoubleを保持すると、C#とVBの両方でキャストが失敗しますが、実行時に失敗します。両方のコンパイラーは、変換を試みる代わりにunbox
命令を発行します。
このシナリオは、DirectCastが非オブジェクト(オブジェクトキーワード)型のコンパイル時型チェックセキュリティについて誤った感覚を持ち、単にバックスペースにすることを意図している理由を最もよく表していると思います。
_float f = 10;
long l = f;
Option Strict On
Dim f As Single = 10
Dim l As Long = f
_
C#コーダーは、floatがlongに直接割り当てられず、コンパイルされないことを発見すると、これを行います。
_long l = (long)f;
_
どちらが正しい。
さて、VB.NETコーダーに目を向けてみましょう。floatはlongに代入可能ではなく、コンパイルもできないことがわかったら、これを試みます。
_Dim l As Long = DirectCast(f, Long)
_
数秒後...
VB.Netプログラマー:「入札をさせてください。コンパイルしてください... !!!」
Googling-fuとMSDN-browsingのしばらく後:
VB.NETプログラマー:「ああ..だから、変数をキャストするためにこのCLngまたはCTypeコンストラクトを使わなければならない」
_Dim l As Long = CLng(f)
_
これが、DirectCastがコンパイル時の型チェックセキュリティについて誤った感覚を持っているということです。 DirectCastは、プログラマがいつ、どこで使用する必要があるかわからない場合に、バックスペースにすることを目的としています。 DirectCastはセキュリティブランケットであり、常時着用されていません
結局使用されない場合、このシナリオでDirectCastはどれほど便利ですか?
[編集]
@Jules
すべてのVB.NETプログラマーがDirectCastの実際の使用方法を知らないというつもりはありません。DirectCastがオブジェクト型(およびオブジェクト内にボックス化されたプリミティブ型)にのみ使用されることを意図していることもあります。 。
既存のC#コードをVB.NETに再コーディングするVB.NETコーダーが間違った結論に到達するシナリオの1つは、予想される(正しいかどうかにかかわらず)言語の対称性です。
彼がコードでこの構造を見ると...
_TextBox txt = (TextBox)sender;
_
...彼はそれをこれに翻訳します:
_Dim txt As TextBox = DirectCast(sender, TextBox)
_
どちらが正しい。
今、私たちプログラマーは対称性を愛しているので、私たちの中には(CLngを知らなければ私もそうかもしれません)このコードを変換する傾向があります...
_/* numbers are stored in file as float(component's file structure
is designed by 3rd party company) */
float f = file.ReadFloat(0);
long l = (long)f; // but we don't care about using the fractional part
_
...これに:
_Dim f As Single = file.ReadFloat(0)
Dim l As Long = DirectCast(f, Long)
_
C#の人がC#コードをVB.NETに変換する人である場合、彼はここで明らかに対称性の欠如に不満を感じるでしょう。
しかし、C#コードをVB.NETに変換するVB.NET担当者にとっては、C#コンパイラーは互換性のない型の割り当てをキャッチしないが、VB.NETはそれをキャッチするという印象を受けます。さて、その明らかな発見のために、彼の同僚といくつかのフォーラムにそのVB.NET機能を自慢します。
しかし、VB.NETプログラマーが最初のコードの意図を誤って推測するという間違いをしないようにしてください。上記のC#のコードフラグメント このように人生を始めた 最初は次のように書かれていました。
_float f = file.ReadFloat(0);
long l = f;
_
そして、それはコンパイルされません、C#コンパイラキャッチ互換性のない型の割り当て、_Option Strict On
_を持つ同等のVB.NETもコンパイルしないのと同じように(ただし、_Option Strict
_はOn
に設定されていますが、長すぎます)。したがって、_(long)
_を使用してfloatをlongに型キャストする必要があります。これになります:long l = (long)f;
このコードを変換するのと同じ方法で、ある変数タイプを別の互換タイプにキャストします...
_TextBox txt = (TextBox)sender;
_
...このコードへ:
_Dim txt As TextBox = DirectCast(sender, Textbox)
_
このコードを変換する必要があります...
_long l = (long)f; // will compile
_
...このコードへ:
_Dim l As Long = DirectCast(f, Long) ' will not compile
_
しかし、互換性のあるプリミティブ型間のキャストでは、コンパイルされません。これは、DirectCastが不足している場所です。上記のC#コードとは対称性がなく、Directという名前にもかかわらず、互換性のあるプリミティブ型のキャストには使用できませんキャスト。
私の見方では、DirectCastはCastObjectという名前にする必要があります。これは、オブジェクトタイプ(およびオブジェクト内にボックス化されたプリミティブタイプ)間でのみキャストできるためです。 DirectCastには、互換性のあるプリミティブ型(整数、二重、およびそれらの下位および上位の対応物)を割り当てるビジネスはありません。互換性のあるプリミティブ型間で割り当てると、DirectCastは有用でなくなります。特に、とにかくバックスペースし、適切なものに置き換えます。
または、私が見る他の方法では、DirectCastコンストラクトを修正して、古い言語と新しい言語のように互換性のある型をキャストできるようにする必要があります。 C、C++、C#、Java、Delphi、Dなど。これを行うと、型キャストに関して、VB.NETが他の言語と大幅に対称的になります。これを行うと、名前がそのタイプ(CInt、CDbl、CSngなど)に直接マッピングされないすべての機能を捨てることができます(仮に、古い関数に依存する他のプログラムを失敗させることはできません)。それらの代わりにDirectCastを使用します。
サンプルコードを本当に実行しようとしましたか?
に関して...
//This code uses a type converter to go across an inheritance tree
string s = "10";
int i = (int)s;
...実行すると仮定しました。また、実行されません
これを試してみましょう。
まず、これについて明確にしましょう。このWILL NOTコンパイル:
//This code uses a type converter to go across an inheritance tree
string s = "10";
int i = (int)s;
VBでは、次を使用します。
Dim s as String = "10"
Dim i as Integer = CType(s, Integer)
C#では、次を使用します。
string s = "10";
int i = Convert.ToInt32(s);
正しい型の場合はキャストし、そうでない場合はInvalidCastExceptionをスローします。
直接キャストはブランチを上下することしかできず、別のブランチに移動することはできません。
その説明から、C#キャストの直接的な同等物になるでしょう。ただし、C#では、キャストダウンにのみキャスト演算子を指定する必要があります。キャストアップは完全にオプションです。例:
// casting down
object t = "some random string needing to be casted down";
string s = (string) t;
// casting up
object a = s;
// explicitly casting up although it's totally optional
object b = (object) s;
C#キャストは、タイプコンバーターを探しません。キャストしようとしている型に対して定義された明示的/暗黙的な演算子オーバーロードのみを検索します。
これはキーワードとしてのC#と同等であることをすでに正しく理解しています。
C#には2種類のキャストがあります。追加のコードがないと、C#のDirectCastキーワードに相当するものはありません。自分で作成せずに最も近いのは、()
。
あなたが持っている:
My_Object c = (My_Object)object
そして
My_Object c = object as My_Object
最初のキャストでは、キャストが失敗するとエラーがスローされます。あなたは言っています、「私はこのオブジェクトが何であるかを知っています、そして、そうでないなら、何か間違っています。」
2番目では、c
には可能な場合は値nullが割り当てられます(値型にnullを割り当てることはできません)。この中で、あなたは「これが何であるかは知っていると思うが、何も間違っていないかもしれないので、エラーを投げないでください」と言っています。
キャストを説明する他の投稿: