web-dev-qa-db-ja.com

直接キャストと 'as'演算子の違い

次のコードを見てください。

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番目のキャスティングはキャスティングではありませんが、意図は得られます)。どちらが好ましいでしょうか?

653
nullDev
string s = (string)o; // 1

スローする InvalidCastExceptionostringでない場合それ以外の場合は、たとえosであっても、onullに割り当てます。

string s = o as string; // 2

nullsでない場合、またはostringである場合は、onullに割り当てます。このため、値型と一緒に使用することはできません(その場合、演算子は決してnullを返すことはできません)。それ以外の場合は、osに割り当てます。

string s = o.ToString(); // 3

onullの場合、 NullReferenceException が発生します。 sがどんな型であっても、o.ToString()oに返すものをすべて割り当てます。


ほとんどのコンバージョンに1を使用してください - それは単純で直接的です。何かが正しい型ではない場合、私は通常例外が発生すると予想するので、私は2をほとんど使用しない傾向があります。エラーコードを使用するように設計されたライブラリ(たとえば、例外を使用する代わりにnull = errorを返す)を使用する場合は、このreturn-nullタイプの機能のみが必要になります。

3はキャストではなく、単なるメソッド呼び出しです。文字列でないオブジェクトの文字列表現が必要なときに使用してください。

779
Sander
  1. string s = (string)o;何かがあるべきときに使う間違いなくそれ以外のもの。
  2. string s = o as string;何かあるかもしれませんそれ以外の場合に使用します。
  3. string s = o.ToString();あなたがそれが何であるかを気にしないけれどもあなたが単に利用可能な文字列表現を使いたいときに使います。
324
Quibblesome

それは本当にあなたがoが文字列であるかどうか知っているかどうかそしてあなたがそれをどうしたいのかにかかっています。あなたのコメントがoが本当に文字列であることを意味するのであれば、私はストレート(string)oキャストを好むでしょう - 失敗することはまずありません。

ストレートキャストを使用する最大の利点は、失敗したときに InvalidCastException が返されることです。

as演算子を使用して、oが文字列ではない場合、snullに設定されます。これがわからない場合やsをテストする場合に便利です。

string s = o as string;
if ( s == null )
{
    // well that's not good!
    gotoPlanB();
}

ただし、そのテストを実行しない場合は、後でsを使用して NullReferenceException がスローされます。ほとんどすべての行が変数を間接参照していて1つをスローする可能性があるため、これらはより一般的であり、たくさんいったん発生すると追跡するのが難しくなります。 。一方、値型(任意のプリミティブ、または DateTime などの構造体)にキャストしようとしている場合は、ストレートキャストを使用する必要があります - asは機能しません。

文字列への変換の特別な場合では、すべてのオブジェクトがToStringを持つので、oがnullでなく、ToStringメソッドがあなたが望むことをするならあなたの3番目のメソッドは問題ないかもしれません。

26
Blair Conrad

どの型にキャストできるかがすでにわかっている場合は、Cスタイルのキャストを使用します。

var o = (string) iKnowThisIsAString; 

明示的な型強制を実行できるのはCスタイルのキャストでのみです。

それが目的の型であるかどうかわからず、使用している場合はas keywordを使用します。

var s = o as string;
if (s != null) return s.Replace("_","-");

//or for early return:
if (s==null) return;

asは型変換演算子を呼び出しません。オブジェクトがnullでなく、指定された型である場合に限り、null以外になります。

ToString()を使用して、文字列にキャストできない場合でも、人間が判読できる任意のオブジェクトの文字列表現を取得します。

9
Mark Cidade

AsControlは、FindControlメソッドを使用するときにasキーワードが適しています。

Hyperlink link = this.FindControl("linkid") as Hyperlink;
if (link != null)
{
     ...
}

これは、直接キャストの場合のようにobjectから型変換された変数をキャストするのではなく、型指定された変数を操作できることを意味します。

object linkObj = this.FindControl("linkid");
if (link != null)
{
     Hyperlink link = (Hyperlink)linkObj;
}

大したことではありませんが、コード行と変数割り当てを節約し、さらに読みやすくなります。

7
Glenn Slaven

'as'は 'is'を基にしています。これは実行時にオブジェクトが多相的に互換性があるかどうかをチェックし(基本的にキャストが可能な場合)、チェックが失敗するとnullを返します。

これら二つは同等です:

'as'を使う:

string s = o as string;

'is'を使う:

if(o is string) 
    s = o;
else
    s = null;

逆に、Cスタイルのキャストは実行時にも行われますが、キャストができない場合は例外がスローされます。

重要な事実を追加するだけです:

'as'キーワードは参照型に対してのみ機能します。できません。

// I swear i is an int
int number = i as int;

そのような場合は、キャストを使用する必要があります。

6
Sergio Acosta

2は派生型へのキャストに役立ちます。

aが動物であるとします。

b = a as Badger;
c = a as Cow;

if (b != null)
   b.EatSnails();
else if (c != null)
   c.EatGrass();

aは最小限のキャストでフィードされます。

5
Joel in Gö

直接キャストがないため、 "(string)o"はInvalidCastExceptionになります。

"o as string"を指定すると、例外がスローされるのではなく、sがnull参照になります。

"o.ToString()"は、それ自体はキャストではありません。オブジェクトによって実装されるメソッドです。したがって、何らかの方法で、.netのすべてのクラスによって実装されます。呼び出されたクラスで、文字列を返します。

文字列に変換するためのConvert.ToString(someType instanceOfThatType)もあります。ここで、someTypeは一連の型の1つであり、基本的にはフレームワークの基本型です。

4
Rob

このページで実行されている実験によると、 http://www.dotnetguru2.org/sebastienros/index.php/2006/02/24/cast_vs_as

(このページには「不正な参照元」エラーが表示されることがあります。表示される場合は更新してください)

結論として、 "as"演算子は通常キャストよりも高速です。時には何倍も速く、時にはほんの少しだけ速くなります。

私は個人的に "as"ということも読みやすいです。

それで、それはより速くそして「より安全」であり(例外を投げられない)、そしておそらくもっと読みやすいので、私はいつも「as」を使うことを勧めます。

4
Brady Moritz
string s = o as string; // 2

ダブルキャストのパフォーマンスペナルティを回避するため、推奨されます。

3
Chris S

私が何かを追加する可能性がある場合、与えられたすべての答えは良いです:直接文字列のメソッドやプロパティ(例えばToLower)を使用するには書くことはできません:

(string)o.ToLower(); // won't compile

あなただけ書くことができます:

((string)o).ToLower();

しかし、代わりに書くことができます:

(o as string).ToLower();

asオプションは読みやすくなっています(少なくとも私の意見では)。

3
BornToCode

2人は概念的に異なるようです。

ダイレクトキャスティング

型は厳密に関連している必要はありません。それはあらゆる種類のフレーバーがあります。

  • カスタムの暗黙的/明示的キャスト:通常、新しいオブジェクトが作成されます。
  • Value Type Implicit:情報を失うことなくコピーします。
  • Value Type Explicit:コピーや情報が失われる可能性があります。
  • IS-A関係:参照型を変更します。それ以外の場合は例外をスローします。
  • 同タイプ:「キャストは冗長です」。

オブジェクトが何か他のものに変換されようとしているように感じます。

AS演算子

型は直接の関係にあります。のように:

  • 参照型:IS-A関係オブジェクトは常に同じで、参照が変わるだけです。
  • 値のタイプ:コピーボクシングおよびnull許容タイプ。

あなたがオブジェクトを別の方法で処理しようとしているように感じます。

サンプルとイリノイ州

    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
    }
3
Lucas Teixeira

次のas演算子の詳細に注目してください。

https://docs.Microsoft.com/ja-jp/dotnet/csharp/language-reference/keywords/as

As演算子は、参照変換、NULL可能変換、およびボクシング変換のみを実行することに注意してください。 as演算子は、ユーザー定義の変換など、他の変換は実行できません。その代わりに、キャスト式を使用して実行します。

1
Vadim S.

アプリケーションの論理的なコンテキストでstringが唯一の有効な型である場合は、直接キャストstring s = (string) o;を使用してください。このアプローチでは、InvalidCastExceptionを取得し、 Fail-fast の原則を実装します。あなたのロジックは無効な型をそれ以上渡すことから保護されるか、as演算子が使われるならばNullReferenceExceptionを受け取ります。

ロジックがいくつかの異なる型を期待している場合は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;
 }
0
Dmitry

誰もそれを述べなかったので、キーワードによってJavaにinstanceOfに最も近いはこれです:

obj.GetType().IsInstanceOfType(otherObj)
0
Bennett Yeo

潜在的にnullになる可能性がある(任意の型の)文字列表現を取得しようとするときは、次のコード行を使用します。コンパクトで、ToString()を呼び出し、nullを正しく処理します。 oがnullの場合、sはString.Emptyを含みます。

String s = String.Concat(o);
0
xtrem

C#では、次の2つの型の変換(キャスト)がサポートされています。

|

(C)v

•与えられた式でvの静的型をcに変換する

•vの動的タイプがc、またはcのサブタイプの場合にのみ可能

•そうでない場合は、InvalidCastExceptionがスローされます。

|

Cとしてv

•(c)vの致命的でない変形

•したがって、与えられた式でvの静的型をcに変換する

•vの動的型がc、またはcのサブタイプではない場合は、nullを返します。

0
user4931677