行の下の答えは2008年に書かれました。
C#7では、パターンマッチングが導入されました。これはas
、次のように記述できるように、演算子に代わるものです。
if (randomObject is TargetType tt)
{
// Use tt here
}
注tt
この後範囲ではまだですが、確かに割り当てられていません。(これはif
本体内で確実に割り当てられます。)場合によっては少し煩わしいので、すべてのスコープで可能な限り少ない数の変数を導入することに本当に関心がある場合はis
、キャストを続けて使用することもできます。
これまでの回答(この回答を開始した時点では!)は、どれを使用する価値があるかを本当に説明しているとは思いません。
これを行わないでください:
// Bad code - checks type twice for no reason
if (randomObject is TargetType)
{
TargetType foo = (TargetType) randomObject;
// Do something with foo
}
このチェックは2回行われるだけでrandomObject
なく、ローカル変数ではなくフィールドの場合、さまざまなチェックを行う場合があります。「if」が通過しても、別のスレッドがrandomObject
2つの値を変更すると、キャストが失敗する可能性があります。
場合はrandomObject
、本当に必要があるのインスタンスでTargetType
、それは、その後、鋳造、手段はバグがあること、ない場合、すなわち適切なソリューションです。これにより、すぐに例外がスローされます。つまり、誤った仮定の下ではこれ以上の作業は行われず、例外はバグのタイプを正しく示します。
// This will throw an exception if randomObject is non-null and
// refers to an object of an incompatible type. The cast is
// the best code if that's the behaviour you want.
TargetType convertedRandomObject = (TargetType) randomObject;
場合randomObject
かもしれないのインスタンスであるTargetType
とTargetType
参照型である、このようなコードを使用します。
TargetType convertedRandomObject = randomObject as TargetType;
if (convertedRandomObject != null)
{
// Do stuff with convertedRandomObject
}
場合randomObject
かもしれないのインスタンスであるTargetType
とTargetType
値型である、我々は使用できないas
とTargetType
、それ自体が、我々はNULL可能タイプを使用することができます。
TargetType? convertedRandomObject = randomObject as TargetType?;
if (convertedRandomObject != null)
{
// Do stuff with convertedRandomObject.Value
}
(注:現在、これは+キャストよりも実際には低速です。よりエレガントで一貫性があると思いますが、それで完了です。)
変換された値が本当に必要ないが、それが TargetTypeのインスタンスであるかどうかを知る必要があるだけの場合、is
オペレーターはあなたの友達です。この場合、TargetTypeが参照型であるか値型であるかは関係ありません。
is
(Tが参照型であるかどうかがわからない場合があるため、次のように使用できないため)ジェネリックが関係する他のケースもあるかもしれませんが、比較的あいまいです。
私はこれまでほとんど確実にis
値型のケースを使用してきましたが、null許容型とas
一緒に使用することは考えていませんでした:)
編集:上記のいずれも、値型の場合を除いて、パフォーマンスについて説明していないことに注意してください。ここで、null許容値型へのボックス化解除は実際には低速ですが、一貫しています。
naaskingの回答によると、is-and-castまたはis-and-asはどちらも、以下のコードに示すように、最新のJITでas-and-null-checkと同じくらい高速です。
using System;
using System.Diagnostics;
using System.Linq;
class Test
{
const int Size = 30000000;
static void Main()
{
object[] values = new object[Size];
for (int i = 0; i < Size - 2; i += 3)
{
values[i] = null;
values[i + 1] = "x";
values[i + 2] = new object();
}
FindLengthWithIsAndCast(values);
FindLengthWithIsAndAs(values);
FindLengthWithAsAndNullCheck(values);
}
static void FindLengthWithIsAndCast(object[] values)
{
Stopwatch sw = Stopwatch.StartNew();
int len = 0;
foreach (object o in values)
{
if (o is string)
{
string a = (string) o;
len += a.Length;
}
}
sw.Stop();
Console.WriteLine("Is and Cast: {0} : {1}", len,
(long)sw.ElapsedMilliseconds);
}
static void FindLengthWithIsAndAs(object[] values)
{
Stopwatch sw = Stopwatch.StartNew();
int len = 0;
foreach (object o in values)
{
if (o is string)
{
string a = o as string;
len += a.Length;
}
}
sw.Stop();
Console.WriteLine("Is and As: {0} : {1}", len,
(long)sw.ElapsedMilliseconds);
}
static void FindLengthWithAsAndNullCheck(object[] values)
{
Stopwatch sw = Stopwatch.StartNew();
int len = 0;
foreach (object o in values)
{
string a = o as string;
if (a != null)
{
len += a.Length;
}
}
sw.Stop();
Console.WriteLine("As and null check: {0} : {1}", len,
(long)sw.ElapsedMilliseconds);
}
}
私のラップトップでは、これらはすべて約60msで実行されます。注意すべき2つの点:
- それらの間に大きな違いはありません。(実際には、としてプラスヌルチェックは間違いなくする状況があるでは、。遅くなり、それは密封されたクラスのためだから上記のコードは、実際に型チェック容易になります。もしあなたのインターフェイスのためにしているチェック、バランスのヒントわずかas-plus-null-checkを支持します。)
- それらはすべてめちゃくちゃ速いです。これは、単純ではないでしょう、あなたが本当にやろうとしていないされていない限り、あなたのコード内のボトルネックになることは何も、その後値を持ちます。
したがって、パフォーマンスについては心配しないでください。正確さと一貫性について心配しましょう。
is-and-cast(またはis-and-as)は、変数を処理するときにどちらも安全ではないことを維持します。テストとキャストの間の別のスレッドにより、参照する値の型が変わる可能性があるためです。それはかなりまれな状況ですが、私は一貫して使用できる規則を持っていると思います。
また、null-as-then-null-checkにより、懸念をより適切に分離できると私は主張します。変換を試みる1つのステートメントと、その結果を使用する1つのステートメントがあります。IS-とキャスト又はあるアンドとして機能試験と、その後値を変換するための別の試み。
別の言い方をすれば、誰かがこれまでに書いたでしょう:
int value;
if (int.TryParse(text, out value))
{
value = int.Parse(text);
// Use value
}
is-and-castがやっていることのようなものですが、明らかにかなり安価です。