次のコードを見てください。
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
スローする InvalidCastExceptiono
が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
o
がnull
の場合、 NullReferenceException が発生します。 s
がどんな型であっても、o.ToString()
がo
に返すものをすべて割り当てます。
ほとんどのコンバージョンに1を使用してください - それは単純で直接的です。何かが正しい型ではない場合、私は通常例外が発生すると予想するので、私は2をほとんど使用しない傾向があります。エラーコードを使用するように設計されたライブラリ(たとえば、例外を使用する代わりにnull = errorを返す)を使用する場合は、このreturn-nullタイプの機能のみが必要になります。
3はキャストではなく、単なるメソッド呼び出しです。文字列でないオブジェクトの文字列表現が必要なときに使用してください。
string s = (string)o;
何かがあるべきときに使う間違いなくそれ以外のもの。string s = o as string;
何かあるかもしれませんそれ以外の場合に使用します。string s = o.ToString();
あなたがそれが何であるかを気にしないけれどもあなたが単に利用可能な文字列表現を使いたいときに使います。それは本当にあなたがo
が文字列であるかどうか知っているかどうかそしてあなたがそれをどうしたいのかにかかっています。あなたのコメントがo
が本当に文字列であることを意味するのであれば、私はストレート(string)o
キャストを好むでしょう - 失敗することはまずありません。
ストレートキャストを使用する最大の利点は、失敗したときに InvalidCastException が返されることです。
as
演算子を使用して、o
が文字列ではない場合、s
はnull
に設定されます。これがわからない場合や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番目のメソッドは問題ないかもしれません。
どの型にキャストできるかがすでにわかっている場合は、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()を使用して、文字列にキャストできない場合でも、人間が判読できる任意のオブジェクトの文字列表現を取得します。
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;
}
大したことではありませんが、コード行と変数割り当てを節約し、さらに読みやすくなります。
'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;
そのような場合は、キャストを使用する必要があります。
2は派生型へのキャストに役立ちます。
aが動物であるとします。
b = a as Badger;
c = a as Cow;
if (b != null)
b.EatSnails();
else if (c != null)
c.EatGrass();
aは最小限のキャストでフィードされます。
直接キャストがないため、 "(string)o"はInvalidCastExceptionになります。
"o as string"を指定すると、例外がスローされるのではなく、sがnull参照になります。
"o.ToString()"は、それ自体はキャストではありません。オブジェクトによって実装されるメソッドです。したがって、何らかの方法で、.netのすべてのクラスによって実装されます。呼び出されたクラスで、文字列を返します。
文字列に変換するためのConvert.ToString(someType instanceOfThatType)もあります。ここで、someTypeは一連の型の1つであり、基本的にはフレームワークの基本型です。
このページで実行されている実験によると、 http://www.dotnetguru2.org/sebastienros/index.php/2006/02/24/cast_vs_as
(このページには「不正な参照元」エラーが表示されることがあります。表示される場合は更新してください)
結論として、 "as"演算子は通常キャストよりも高速です。時には何倍も速く、時にはほんの少しだけ速くなります。
私は個人的に "as"ということも読みやすいです。
それで、それはより速くそして「より安全」であり(例外を投げられない)、そしておそらくもっと読みやすいので、私はいつも「as」を使うことを勧めます。
string s = o as string; // 2
ダブルキャストのパフォーマンスペナルティを回避するため、推奨されます。
私が何かを追加する可能性がある場合、与えられたすべての答えは良いです:直接文字列のメソッドやプロパティ(例えばToLower)を使用するには書くことはできません:
(string)o.ToLower(); // won't compile
あなただけ書くことができます:
((string)o).ToLower();
しかし、代わりに書くことができます:
(o as string).ToLower();
as
オプションは読みやすくなっています(少なくとも私の意見では)。
2人は概念的に異なるようです。
ダイレクトキャスティング
型は厳密に関連している必要はありません。それはあらゆる種類のフレーバーがあります。
オブジェクトが何か他のものに変換されようとしているように感じます。
AS演算子
型は直接の関係にあります。のように:
あなたがオブジェクトを別の方法で処理しようとしているように感じます。
サンプルとイリノイ州
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
}
次のas演算子の詳細に注目してください。
https://docs.Microsoft.com/ja-jp/dotnet/csharp/language-reference/keywords/as
As演算子は、参照変換、NULL可能変換、およびボクシング変換のみを実行することに注意してください。 as演算子は、ユーザー定義の変換など、他の変換は実行できません。その代わりに、キャスト式を使用して実行します。
アプリケーションの論理的なコンテキストで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;
}
誰もそれを述べなかったので、キーワードによってJavaにinstanceOfに最も近いはこれです:
obj.GetType().IsInstanceOfType(otherObj)
潜在的にnullになる可能性がある(任意の型の)文字列表現を取得しようとするときは、次のコード行を使用します。コンパクトで、ToString()を呼び出し、nullを正しく処理します。 oがnullの場合、sはString.Emptyを含みます。
String s = String.Concat(o);
C#では、次の2つの型の変換(キャスト)がサポートされています。
|
(C)v
•与えられた式でvの静的型をcに変換する
•vの動的タイプがc、またはcのサブタイプの場合にのみ可能
•そうでない場合は、InvalidCastExceptionがスローされます。
|
Cとしてv
•(c)vの致命的でない変形
•したがって、与えられた式でvの静的型をcに変換する
•vの動的型がc、またはcのサブタイプではない場合は、nullを返します。