51

C#にはVB.NETのDirectCastと同等のものがありますか?

()キャストと'as'キーワードがあることは知っていますが、それらはCTypeとTryCastに並んでいます。

明確にするために、これらのキーワードは次のことを行います。

CType /()キャスト:すでに正しい型である場合はキャストします。そうでない場合は、型コンバーターを探して呼び出します。タイプコンバータが見つからない場合は、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)
4

11 に答える 11

14

必要な機能が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;
}
于 2010-04-21T15:31:13.760 に答える
8

2 番目の更新:

DirectCastOK、これは基本的に VB.NET で行うことを行うと提案されている 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;
}

上記の方法の問題点は次のとおりです。

  1. where T : class制約がありますが、そうではありDirectCastません。
  2. それはその引数をSystem.Object-- 繰り返しますが、真実ではありませんDirectCast(少なくとも私が知っていることではありません)。
  3. 不必要に使用します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>方法はまったく不要になります。

ここで、 VB.NET と C# の間DirectCastで と のキャスト()が「異なる」方法の例を示します。

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

1 つがコンパイルされ、もう 1 つがコンパイルされません。しかし、そのコードを見てください。オブジェクトの型が既にわかっている場合、何の意味があるでしょうか? DirectCastDirectCastVB.NETでは上記のコードのように呼び出す理由がないため、これは現実的な比較ではありません。(ある型であることがわかってSystem.Int32System.Int64いる値をVB.NETの型の値に変換したい場合CLngは、 ではなくを使用しDirectCastます)。以下のコードは実際に同等です。System.ObjectDirectCast

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

したがってDirectCast、VB.NET では、それを実際に使用することが理にかなっているシナリオ (つまり、コンパイル時にオブジェクトの型がわからない場合) では、C#のストレート スタイル キャストと同じである()と主張しています。


編集:まあ、コンパイルされなかったいくつかの VB コードを投稿したことを恥じてください。私が言ったことを再考した後、私は2 番目の回答を撤回しますが、最初の回答は維持します。

DirectCast不明な型のオブジェクトを取得して目的の型にキャストしようとするの使用法について言及している場合、C# の () キャストと同じです。

VB:

Dim o As Object = SomeObject()
Dim i As Integer = DirectCast(o, Integer)

C#:

object o = SomeObject();
int i = (int)o;

これは、oが として入力された場合、C# でSystem.Object()操作がそれをボックス化解除しようとするためです。タイプが正確に一致しない場合、これは失敗します。たとえば、oが boxed のSystem.Double場合、 はに変換する前にとしてボックス化解除する必要(int)oがあるため、例外がスローされます (信じられない場合は、自分で試してみてください!)。o System.DoubleSystem.Int32


注: は拡大変換を実行DirectCastないため、以下は不正確です。いずれにせよ、後世に残します。

一方、拡大変換と縮小変換を処理する場合()、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;
于 2010-04-21T16:06:47.387 に答える
1

実際、コンパイラは、型付き変数を他の型に変換できないと推測した場合、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から整数値へのロードも防止します。これはOPが主張していることであり、C#にはDirectCastがなく、DirectCastはさまざまなタイプの変数の割り当てを防ぐことができますが、「C#にはこのDirectCastがないため」、さまざまなタイプの割り当てでサイレントエラーが発生します。しかし、ご覧のとおり、そうではありません。C#のキャストは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)

うーん..OPの混乱は、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)に置き換える必要があります。

于 2010-04-21T15:59:25.010 に答える
1

自分で実装できます:

static T CastTo<T>(this object obj) { return (T)obj; }

次のように使用します。

3.5.CastTo<int>(); //throws InvalidCastException.

ジェネリックは実行時に「解決」されますが、型変換はコンパイル時に解決されるため、これは機能し、ユーザー定義のコンバーターは必要ありませんT。同様の実装でTあるため、ランタイムにはカスタム変換を解決するための情報がありません。

于 2010-04-21T16:01:03.313 に答える
0

C# には 2 種類のキャストがあります。追加のコードがなければ、C# の DirectCast キーワードに相当するものはありません。自分で作成せずに最も近いのは、を使用すること()です。

あなたが持っている:

My_Object c = (My_Object)object

My_Object c = object as My_Object

最初のものでは、キャストが失敗するとエラーがスローされます。あなたは、「私はこの物体が何であるかを知っています。もしそうでなければ、何かが間違っています」と言っています。

2 番目でcは、可能な場合に値 null が割り当てられます (値の型に null を割り当てることはできません)。この例では、「これが何であるかはわかっていると思いますが、そうでない場合はエラーをスローしないでください。何も問題がない可能性があるためです」と言っています。

キャストを説明する他の投稿:

明示的な型キャストと暗黙的な型キャストの違いは何ですか?

于 2010-04-21T14:38:41.163 に答える
0

サンプル コードを実際に実行しようとしましたか?

それにかんする...

//This code uses a type converter to go across an inheritance tree
string s = "10";
int i = (int)s;

...あなたはそれが実行されると仮定しました。また、実行されません。

于 2010-04-21T15:28:38.270 に答える
0

これを試してみましょう。

まず、これについて明確にさせてください。これはコンパイルされません:

//This code uses a type converter to go across an inheritance tree
string s = "10";
int i = (int)s;

VB の CType

VB では、次を使用します。

Dim s as String = "10"
Dim i as Integer = CType(s, Integer)

C# では、次のように使用します。

string s = "10";
int i = Convert.ToInt32(s);

VB の DirectCast

正しいタイプの場合はキャストし、そうでない場合は 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# キャストは型コンバーターを探しません。キャストしようとしている型に対して定義された明示的/暗黙的な演算子のオーバーロードのみを探します。


VB の TryCast

これがキーワードとして C# に相当することは既に正しく理解しています。

于 2010-04-21T15:42:15.467 に答える
-1

このシナリオは、DirectCastが非オブジェクト(オブジェクトキーワード)型のセキュリティをチェックするコンパイル時型の誤った感覚を持っている理由を最もよく要約していると思います。

float f = 10;
long l = f;
Option Strict On
Dim f As Single = 10
Dim l As Long = f

AC#コーダーは、floatがlongに直接割り当てられず、コンパイルされないことを発見すると、次のことを行います。

long l = (long)f;

どちらが正しい。

ここで、VB.NETコーダーに目を向けましょう。フロートがロングに割り当てられず、コンパイルされないことがわかったら、これを試みます。

Dim l As Long = DirectCast(f, Long)

数秒後...

VB.NETプログラマー:「入札をさせてください、コンパイルしてください...!!!」

いくつかのグーグル-fuとMSDN-ブラウジングの瞬間の後:

VB.NETプログラマー:「ああ、変数をキャストするためにこのCLngまたはCType構造を使用する必要があります」

Dim l As Long = CLng(f)

これは、DirectCastがコンパイル時の型チェックのセキュリティについて誤った感覚を持っていることを意味していました。DirectCastは、プログラマーがいつどこで使用すべきかわからない場合にバックスペースを設定することを目的としています。DirectCastは、常に着用されているわけではないセキュリティブランケットです。

結局使用されない場合、このシナリオでDirectCastはどの程度役に立ちますか?


[編集]

@ジュール

すべての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#コンパイラは、互換性のない型の割り当てをキャッチします。これは、同等のVB.NETでもコンパイルされないのと同じです(ただし、がに設定されているOption Strict On場合にのみコンパイルされませんが、あまりにも寛大です)。したがって、を使用してfloatをlongに型キャストする必要があります。これになります:Option StrictOn(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 Castという名前にもかかわらず、互換性のあるプリミティブ型のキャストには使用できません。

私の見方では、DirectCastはCastObjectという名前にする必要がありますこれは、とにかくオブジェクトタイプ(およびオブジェクトでボックス化されたプリミティブタイプ)間でのみキャストできるためです。DirectCastは、互換性のあるプリミティブ型(integer、double、およびそれらの下位と上位の対応物)を割り当てることには実際には関係ありません。互換性のあるプリミティブ型間で割り当てる場合、DirectCastは役に立たなくなります。特に、とにかくバックスペースを作成して、適切なものに置き換えます。

または、別の見方をすれば、DirectCast構造を修正して、C、C ++、C#、Java、Delphi、Dなど、新旧の言語と同じように互換性のある型をキャストできるようにする必要があります。型キャストに関しては、他の言語に対してVB.NETに大きな対称性を提供します。これを行うことで、名前がその型に直接マップされない多数の関数(CInt、CDbl、CSngなど)をすべて破棄することもできます(仮想的にのみ、古い関数に依存する他のプログラムを失敗させることはできません)。 。それらの代わりにDirectCastを使用します。

于 2010-04-21T19:01:37.640 に答える
-1

() キャストは同じである必要があります。InvalidCastException をスローします。C#でこれを試してみてください:

 string t = "hello";
 object x = t;
 int j = (int) x;
于 2010-04-21T14:38:25.163 に答える