c# - 違い - vb.net ctype
ダイレクトキャストと '演算子' (12)
次のコードを考えてみましょう:
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番目のキャストはキャストではありませんが、目的は得られます)。 どちらが優先されるべきですか?
- 何かが間違いなく他のものになるべきときに使う。
- 何かが別のものであるときに使用します。
- それが何であるか気にしなくても、使用できる文字列表現を使用したいときに使用します。
"(文字列)o"は、直接キャストがないため、InvalidCastExceptionが発生します。
"o as string"は、例外がスローされるのではなく、sがnull参照になります。
"o.ToString()"は、あらゆる種類の型のキャストではなく、オブジェクトによって実装されるメソッドなので、あるクラスまたは別のクラスでは、.netの各クラスによって、そのクラスが呼び出され、文字列を返します。
文字列に変換するためにConvert.ToString(someType instanceOfThatType)があることを忘れないでください。someTypeは型のセットの1つで、基本的にフレームワークの基本タイプです。
2は派生型へのキャストに便利です。
aがAnimalであると仮定します:
b = a as Badger;
c = a as Cow;
if (b != null)
b.EatSnails();
else if (c != null)
c.EatGrass();
最低限のキャストを与えられます。
2人は概念的に異なっているようです。
ダイレクトキャスティング
タイプは厳密に関連する必要はありません。 すべての種類のフレーバーが付属しています。
- カスタムの暗黙的/明示的なキャスト:通常、新しいオブジェクトが作成されます。
- 値のタイプ暗黙的:情報を失うことなくコピーします。
- 値のタイプExplicit:コピーと情報が失われる可能性があります。
- IS-A関係:参照タイプを変更し、そうでない場合は例外をスローします。
- 同じタイプ: 'Casting is redundant'。
オブジェクトが他のものに変換されるように感じます。
AS演算子
型は直接の関係を持っています。 次のように:
- 参照の種類: IS-Aの関係オブジェクトは常に同じで、参照の変更のみです。
- 値の種類:ボクシングとヌル入力可能な型をコピーします。
オブジェクトを別の方法で処理しようとしているように感じます。
サンプルと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
}
FindControlメソッドを使用すると、asp.netではasキーワードが有効です。
Hyperlink link = this.FindControl("linkid") as Hyperlink;
if (link != null)
{
...
}
これは、直接型変換のようにobject
からキャストするのではなく、型付き変数を操作できることを意味します。
object linkObj = this.FindControl("linkid");
if (link != null)
{
Hyperlink link = (Hyperlink)linkObj;
}
それは巨大なことではありませんが、コードの行と変数の割り当てを節約し、読みやすくします
このページでの実験によると: http://www.dotnetguru2.org/sebastienros/index.php/2006/02/24/cast_vs_as : http://www.dotnetguru2.org/sebastienros/index.php/2006/02/24/cast_vs_as
(このページには「不正な参照元」のエラーが表示されることがあります。その場合はリフレッシュするだけです)
結論として、 "as"演算子は通常、キャストより高速です。 時には何倍も速く、時にはほんの少し速い。
私はまるで "as"という言葉も読みやすくなっています。
だから、それは速く、より安全で(例外を投げることはない)、読みやすくなるので、私はいつもasを使うことをお勧めします。
キャストできるタイプがすでに分かっている場合は、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()を使用して、オブジェクトの人間が読める文字列表現を取得します。
ダイレクトキャストstring s = (string) o;
あなたのアプリケーションstring
論理的な文脈で唯一の有効な型であれば。 この方法では、 InvalidCastException
し、 Fail-fast原則が実装されます。 あなたのロジックは、無効な型をさらに渡すことから保護さas
かas
演算子as
使用さas
場合はNullReferenceExceptionを取得as
ます。
ロジックがいくつかの異なる型を予期している場合、 string s = o as string;
キャストstring s = o as string;
それをnull
チェックするか、またはis
演算子を使用しnull
。
新しいクールな機能がキャストを簡素化するために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;
}
私が何かを加えるかもしれないなら、与えられたすべての答えは良いです:文字列のメソッドとプロパティ(例えばToLower)を直接使うには、以下を書くことはできません:
(string)o.ToLower(); // won't compile
あなたは書くことができます:
((string)o).ToLower();
代わりに書くことができます:
(o as string).ToLower();
as
オプションは読みやすく(少なくとも私の意見では)。
私はas演算子の以下の特質に注目したいと思います:
https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/as
as演算子は、参照コンバージョン、null可のコンバージョン、ボクシングコンバージョンのみを実行することに注意してください。 as演算子は、ユーザー定義の変換などの他の変換は実行できません。変換はキャスト式を使用して実行する必要があります。
string s = (string)o; // 1
InvalidCastException o
がstring
でない場合 それ以外の場合は、 o
がnull
場合でもo
にs
代入しnull
。
string s = o as string; // 2
o
がstring
ない場合、またはo
がnull
場合は、 s
null
を代入しnull
。 このため、値型では使用できません(その場合、演算子はnull
を返すことはできません)。 それ以外の場合は、 o
にs
代入します。
string s = o.ToString(); // 3
o
がnull
場合、 NullReferenceException null
。 o.ToString()
がどんなタイプo
もs
に返すものをo.ToString()
ます。
ほとんどのコンバージョンには1を使用します。シンプルで簡単です。 私は2をほとんど使用しない傾向があります。なぜなら、何かが正しいタイプでないと、通常、例外が発生すると予想します。 私は、エラーコード(例:例外を使用する代わりにnullを返す)を使用するライブラリの設計で、このリターンnull型の機能が必要であることを見てきました。
3はキャストではなく、単なるメソッド呼び出しです。 文字列以外のオブジェクトの文字列表現が必要なときに使用します。
string s = o as string; // 2
ダブルキャスティングのパフォーマンス上のペナルティを避けるため、推奨されます。