web-dev-qa-db-ja.com

C# "as"キャストとクラシックキャスト

可能性のある複製:
CLRでの「as」キーワードの使用とキャスト

最近、キャストの別の方法について学びました。使用するのではなく

SomeClass someObject = (SomeClass) obj;

次の構文を使用できます。

SomeClass someObject = obj as SomeClass;

objがSomeClassではない場合、クラスキャスト例外をスローするのではなく、nullを返すようです。

キャストが失敗した場合、これによりNullReferenceExceptionが発生する可能性があり、someObject変数にアクセスしようとしています。だから私はこの方法の背後にある理論的根拠は何ですか? (古い)キャストではなく、このキャスト方法を使用する必要があるのはなぜですか?失敗したキャスト「ディープ」の問題をコードに移すだけのようです。

124
Chris

「クラシック」メソッドを使用すると、キャストが失敗した場合、例外がスローされます。 asメソッドを使用すると、nullになります。これをチェックして、例外がスローされるのを防ぐことができます。

また、参照型では "as"のみを使用できるため、値型に型キャストする場合は、引き続き "classic"メソッドを使用する必要があります。

注:

asメソッドは、null値を割り当てることができるタイプにのみ使用できます。これは参照型のみを意味しますが、.NET 2.0が登場すると、null許容値型の概念が導入されました。これらのタイプにはnull値を割り当てることができるため、as演算子で使用するのに有効です。

155
Brian Ball

ヌル比較はMUCH例外をスローしてキャッチするよりも高速です。例外には大きなオーバーヘッドがあります-スタックトレースをアセンブルする必要があるなど。

例外は予期しない状態を表す必要がありますが、これは多くの場合、状況を表していません(asがより適切に機能する場合)。

31
Matěj Zábský

場合によっては、例外よりもnullを扱う方が簡単です。特に、合体演算子は便利です。

SomeClass someObject = (obj as SomeClass) ?? new SomeClass();

また、オブジェクトのタイプに基づいて分岐している(ポリモーフィズムを使用していない)コードを単純化します。

ClassA a;
ClassB b;
if ((a = obj as ClassA) != null)
{
    // use a
}
else if ((b = obj as ClassB) != null)
{
    // use b
}

MSDNページ で指定されているように、as演算子は次と同等です。

expression is type ? (type)expression : (type)null

より高速な型テストを優先して例外を完全に回避しますが、null(参照型およびNullable<T>)をサポートする型にその使用を制限します。

27
Zooba

as演算子は、いくつかの状況で役立ちます。

  1. オブジェクトが特定のタイプのものであることを知る必要があるだけで、そのタイプのメンバーに具体的に対処する必要がない場合
  2. 例外を避け、代わりにnullを明示的に処理する場合
  3. ユーザー定義の変換だけでなく、オブジェクト間にCLR変換があるかどうかを知りたい。

3番目のポイントは微妙ですが重要です。キャスト演算子で成功するキャストとas演算子で成功するマッピングの間に1-1マッピングはありません。 as演算子はCLR変換に厳密に制限されており、ユーザー定義の変換は考慮されません(キャスト演算子は考慮します)。

具体的には、as演算子は以下のみを許可します(C#lang仕様のセクション7.9.11から)

  • Eのタイプからのアイデンティティ(§6.1.1)、暗黙的な参照(§6.1.6)、ボクシング(§6.1.7)、明示的な参照(§6.2.4)、またはボックス化解除(§6.2.5)の変換が存在しますTへ.
  • EまたはTのタイプは、オープンタイプです。
  • EはNULLリテラルです。
7
JaredPar

asキーワードは、真にわからない変数のタイプを指定する場合に役立ちます。パラメーターの実際のタイプに応じて異なるコードパスに従う単一の関数がある場合、2つの選択肢があります。

まず、通常のキャストを使用します。

if(myObj is string)
{
    string value = (string)myObj;

    ... do something
}
else if(myObj is MyClass)
{
    MyClass = (MyClass)myObj;
}

これには、isを使用してオブジェクトのタイプをチェックし、失敗するものにキャストしようとしないようにする必要があります。また、キャストでis- typeチェックが再度行われるため、これも少し冗長です(必要に応じて例外をスローできるように)。

別の方法は、asを使用することです。

string myString = myObj as string;
MyClass myClass = myObj as MyClass;

if(myString != null)
{

}
else if(myClass != null)
{

}

これにより、コードが多少短くなり、冗長な型チェックも不要になります。

3
Adam Robinson

最良の「ルール」は、「as」キーワードを使用するのは、サブジェクトがキャスト先のオブジェクトにならないことが予想される場合のみだと思います:

var x = GiveMeSomething();

var subject = x as String;

if(subject != null)
{
  // do what you want with a string
}
else
{
  // do what you want with NOT a string
}

ただし、サブジェクトがキャスト先のタイプである必要がある場合は、「クラシックキャスト」と呼んでください。期待するタイプではない場合、例外的な状況に適合する例外が発生するためです。

1
Erik van Brakel

asを使用すると、有効なキャストでない場合はnullが返されます。これにより、try/catchでキャストをラップする以外のことができます。私は古典的なキャストが嫌いです。よくわからない場合は、常にキャストとして使用します。さらに、例外は高価です。ヌルチェックはそうではありません。

1
Dustin Davis

キャストやArgumentNullExceptionなどを使用せずにnull参照を処理することがわかっているメソッドにキャストの結果を渡すと便利だと思います。

私はasの使用をほとんど見つけない傾向があります。

obj as T

より遅い:

if (obj is T)
    ...(T)obj...

asの使用は、私にとって非常にエッジケースシナリオであるため、(より有益な)キャスト例外をキャストおよび処理するだけで使用する一般的なルールを考えることはできません。スタック。

0
Quick Joe Smith

ここでは何も深く起こっているわけではありません。 'as'呼び出しの結果をチェックして、結果がnullであるかどうかを確認します。

キャストが機能することを期待し、例外をスローする場合は、「クラシック」メソッドを使用します。

0
RQDQ

「as」ステートメントを使用して、例外の可能性を回避します。キャストの失敗をロジックで適切に処理できます。オブジェクトが目的のタイプであることが確実な場合にのみ、キャストを使用してください。ほとんどの場合、「as」を使用してからヌルをチェックします。

0
Keith Bluestone