質問
次のコードを考えてみましょう。
void Handler(object o, EventArgs e)
{
// I swear o is a string
string s = (string)o; // 1
//-OR-
string s = o as string; // 2
// -OR-
string s = o.ToString(); // 3
}
3 つのタイプのキャストの違いは何ですか (3 番目のタイプはキャストではありませんが、意図は理解できます)。どちらを優先すべきでしょうか?
解決
string s = (string)o; // 1
投げる 無効なキャスト例外 もし o
ではありません string
. 。それ以外の場合は、割り当て o
に s
, 、 たとえ o
は null
.
string s = o as string; // 2
割り当てる null
に s
もし o
ではありません string
あるいは o
は null
. 。このため、値型では使用できません (演算子は決して値を返すことができません)。 null
その場合)。それ以外の場合は、割り当て o
に s
.
string s = o.ToString(); // 3
原因 NullReferenceException もし o
は null
. 。何でも割り当てます o.ToString()
に戻ります s
, 、どんなタイプであっても o
は。
ほとんどの変換には 1 を使用します。これはシンプルで簡単です。何かが正しい型ではない場合、通常は例外が発生すると予想されるため、私は 2 をほとんど使用しません。私は、この return-null タイプの機能の必要性を認識したのは、エラー コードを使用する不適切に設計されたライブラリ (例:例外を使用する代わりに、null = エラーを返します)。
3 はキャストではなく、単なるメソッド呼び出しです。非文字列オブジェクトの文字列表現が必要な場合に使用します。
他のヒント
string s = (string)o;
何かが必要なときに使用します絶対に 別のものであってください。string s = o as string;
何かのときに使います そうかもしれない もう一つ。string s = o.ToString();
それが何であるかを気にしないときは使用しますが、利用可能な文字列表現を使用したいだけです。
それは本当にあなたが知っているかどうかに依存します o
は文字列であり、それを使って何をしたいのか。あなたのコメントがそういう意味なら o
本当に本当に文字列です、私はストレートの方がいいです (string)o
キャスト - 失敗する可能性は低いです。
ストレート キャストを使用する最大の利点は、失敗したときに 無効なキャスト例外, これにより、何が問題だったのかがほぼわかります。
とともに as
演算子 (場合) o
文字列ではないので、 s
に設定されています null
, 、確信が持てずにテストしたい場合に便利です。 s
:
string s = o as string;
if ( s == null )
{
// well that's not good!
gotoPlanB();
}
ただし、そのテストを実行しない場合は、 s
後で、 NullReferenceException 投げられた。これらはより一般的な傾向にあり、 多く ほぼすべての行が変数を逆参照し、変数をスローする可能性があるため、これらが実際に発生すると、追跡するのが難しくなります。一方、値型 (任意のプリミティブ、または次のような構造体) にキャストしようとしている場合は、 日付時刻)、ストレートキャストを使用する必要があります。 as
機能しません。
文字列に変換する特殊なケースでは、すべてのオブジェクトには ToString
, したがって、3 番目の方法は次の場合には問題ないかもしれません。 o
は null ではないので、 ToString
メソッドはあなたが望むことを行うかもしれません。
キャストできる型がすでにわかっている場合は、C スタイルのキャストを使用します。
var o = (string) iKnowThisIsAString;
C スタイルのキャストを使用した場合のみ、明示的な型強制を実行できることに注意してください。
希望のタイプかどうか分からず、希望のタイプであればそれを使用する場合は、次を使用します。 として キーワード:
var s = o as string;
if (s != null) return s.Replace("_","-");
//or for early return:
if (s==null) return;
ご了承ください として 型変換演算子は呼び出されません。オブジェクトが null ではなく、ネイティブに指定された型である場合にのみ、null 以外になります。
ToString() を使用すると、文字列にキャストできないオブジェクトであっても、人間が判読できる文字列表現を取得できます。
as キーワードは、asp.net で FindControl メソッドを使用するときに適しています。
Hyperlink link = this.FindControl("linkid") as Hyperlink;
if (link != null)
{
...
}
これは、型付き変数をキャストするのではなく、型付き変数を操作できることを意味します。 object
直接キャストの場合と同じように:
object linkObj = this.FindControl("linkid");
if (link != null)
{
Hyperlink link = (Hyperlink)linkObj;
}
これは大したことではありませんが、コード行と変数割り当てが節約され、さらに読みやすくなります。
「as」は「is」に基づいています。これは、オブジェクトが多態性互換であるかどうか (基本的にキャストが可能かどうか) を実行時にチェックし、チェックが失敗した場合は null を返すキーワードです。
これら 2 つは同等です。
「as」を使用する場合:
string s = o as string;
「です」の使用:
if(o is string)
s = o;
else
s = null;
逆に、C スタイルのキャストは実行時にも行われますが、キャストできない場合は例外をスローします。
重要な事実を付け加えておきます。
'as' キーワードは参照型でのみ機能します。次のことはできません:
// I swear i is an int
int number = i as int;
そのような場合は、キャストを使用する必要があります。
2 は、派生型にキャストする場合に便利です。
仮定する ある は動物です:
b = a as Badger;
c = a as Cow;
if (b != null)
b.EatSnails();
else if (c != null)
c.EatGrass();
取得します ある 最小限のキャストで供給されます。
このページで実行された実験によると: http://www.dotnetguru2.org/sebastienros/index.php/2006/02/24/cast_vs_as
(このページでは「不正な参照元」エラーが時々表示されるため、表示された場合は更新してください)
結論として、「as」演算子は通常、キャストよりも高速です。何倍も速い場合もあれば、ぎりぎり速い場合もあります。
個人的には「as」の方が読みやすいと思います。
したがって、より高速で「安全」(例外をスローしない)、そしておそらく読みやすいため、常に「as」を使用することをお勧めします。
"(string)o" は直接キャストがないため、InvalidCastException が発生します。
「o as string」では、例外がスローされるのではなく、s が null 参照になります。
"o.ToString()" は、それ自体はいかなる種類のキャストでもありません。これは、オブジェクトによって実装されるメソッドであり、そのため、何らかの方法で、.net のすべてのクラスによって実装され、 のインスタンスで「何かを実行」します。呼び出されたクラスで文字列を返します。
文字列に変換するには、Convert.ToString(someTypeinstanceOfThatType) もあることを忘れないでください。ここで、someType は型のセットの 1 つであり、本質的にはフレームワークの基本型です。
何かを付け加えれば、与えられた答えはすべて良いものです。文字列のメソッドとプロパティを直接使用するには (例:ToLower) 次のように書くことはできません。
(string)o.ToLower(); // won't compile
次のように書くことしかできません。
((string)o).ToLower();
しかし、代わりに次のように書くこともできます。
(o as string).ToLower();
の as
(少なくとも私の意見では) オプションの方が読みやすいです。
string s = o as string; // 2
ダブルキャストによるパフォーマンスの低下を回避できるため、この方法が推奨されます。
両者は概念的に異なるようです。
ダイレクトキャスト
型は厳密に関連している必要はありません。あらゆる種類の味が揃っています。
- カスタムの暗黙的/明示的キャスト: 通常、新しいオブジェクトが作成されます。
- 暗黙的な値のタイプ: 情報を失わずにコピーできます。
- 値のタイプ 明示的: コピーや情報が失われる可能性があります。
- IS-A 関係: 参照型を変更します。変更しない場合は例外がスローされます。
- 同じタイプ: 「キャスティングは余計だ」。
オブジェクトが別のものに変換されようとしているように感じます。
ASオペレーター
型には直接的な関係があります。次のように:
- 参照タイプ: IS-A関係 オブジェクトは常に同じであり、参照が変更されるだけです。
- 値のタイプ: コピー ボクシング型と null 許容型。
オブジェクトを別の方法で処理しようとしているように感じます。
サンプルとIL
class TypeA
{
public int value;
}
class TypeB
{
public int number;
public static explicit operator TypeB(TypeA v)
{
return new TypeB() { number = v.value };
}
}
class TypeC : TypeB { }
interface IFoo { }
class TypeD : TypeA, IFoo { }
void Run()
{
TypeA customTypeA = new TypeD() { value = 10 };
long longValue = long.MaxValue;
int intValue = int.MaxValue;
// Casting
TypeB typeB = (TypeB)customTypeA; // custom explicit casting -- IL: call class ConsoleApp1.Program/TypeB ConsoleApp1.Program/TypeB::op_Explicit(class ConsoleApp1.Program/TypeA)
IFoo foo = (IFoo)customTypeA; // is-a reference -- IL: castclass ConsoleApp1.Program/IFoo
int loseValue = (int)longValue; // explicit -- IL: conv.i4
long dontLose = intValue; // implict -- IL: conv.i8
// AS
int? wraps = intValue as int?; // nullable wrapper -- IL: call instance void valuetype [System.Runtime]System.Nullable`1<int32>::.ctor(!0)
object o1 = intValue as object; // box -- IL: box [System.Runtime]System.Int32
TypeD d1 = customTypeA as TypeD; // reference conversion -- IL: isinst ConsoleApp1.Program/TypeD
IFoo f1 = customTypeA as IFoo; // reference conversion -- IL: isinst ConsoleApp1.Program/IFoo
//TypeC d = customTypeA as TypeC; // wouldn't compile
}
以下の具体的な内容に注目したいと思います。 として オペレーター:
https://docs.microsoft.com/en-us/dotnet/csharp/ language-reference/keywords/as
ASオペレーターは、参照変換、無視可能な変換、およびボクシング変換のみを実行することに注意してください。ASオペレーターは、ユーザー定義の変換など、他の変換を実行することはできません。これは、キャスト式を使用して実行する必要があります。
null になる可能性のあるもの (任意の型) の文字列表現を取得しようとする場合、私は以下のコード行を好みます。これはコンパクトで、ToString() を呼び出し、null を正しく処理します。o が null の場合、s には String.Empty が含まれます。
String s = String.Concat(o);
誰も言及していないので、キーワードによる Java の instanceOf に最も近いものは次のとおりです。
obj.GetType().IsInstanceOfType(otherObj)
ダイレクトキャストを使用する string s = (string) o;
アプリの論理コンテキストの場合 string
が唯一の有効なタイプです。このアプローチにより、次のことが得られます InvalidCastException
の原則を実装します フェイルファスト. 。ロジックは、無効な型をさらに渡さないように保護されたり、使用された場合に NullReferenceException が発生したりすることはありません。 as
オペレーター。
ロジックが複数の異なる型のキャストを想定している場合 string s = o as string;
そしてそれをチェックしてください null
または使用します is
オペレーター。
キャストとチェックを簡素化する新しいクールな機能が C# 7.0 に登場しました。 パターンマッチング:
if(o is string s)
{
// Use string variable s
}
or
switch (o)
{
case int i:
// Use int variable i
break;
case string s:
// Use string variable s
break;
}
C# では、次の 2 つの形式の型変換 (キャスト) がサポートされています。
|
(履歴書
• 指定された式で v の静的型を c に変換します。
• v の動的タイプが c または c のサブタイプの場合にのみ可能です。
• そうでない場合は、InvalidCastException がスローされます。
|
v として C
• (c) v の非致命的バリアント
• したがって、指定された式で v の静的型を c に変換します。
• v の動的タイプが c でない場合、または c のサブタイプでない場合は、null を返します。