이 줄 아래의 답변은 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
}
이 검사는 두 번뿐만 randomObject
아니라 지역 변수가 아닌 필드 인 경우 다른 것을 검사 할 수 있습니다 . 다른 스레드 randomObject
가 둘 사이의 값을 변경하면 "if"는 통과 할 수 있지만 캐스트가 실패 할 수 있습니다.
경우 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
자체, 그러나 우리는 nullable 형식을 사용할 수 있습니다 :
TargetType? convertedRandomObject = randomObject as TargetType?;
if (convertedRandomObject != null)
{
// Do stuff with convertedRandomObject.Value
}
(참고 : 현재 이것은 실제로 + cast보다 느립니다 . 더 우아하고 일관성이 있다고 생각합니다.)
당신이 정말로 변환 된 값이 필요하지 않습니다,하지만 당신은 그냥 여부를 알 필요가있는 경우 입니다 은 TargetType의 인스턴스, 다음 is
연산자는 당신의 친구입니다. 이 경우 TargetType이 참조 유형인지 또는 값 유형인지는 중요하지 않습니다.
is
유용한 경우 제네릭과 관련된 다른 경우가있을 수 있습니다 (T가 참조 유형인지 여부를 알 수 없기 때문에 사용할 수는 없으므로) 상대적으로 모호합니다.
필자는 is
nullable 유형과 as
함께 사용할 생각을하지 않고 지금까지 값 유형 사례에 거의 확실하게 사용 했습니다.
편집 : 위의 값 중 nullable 값 유형으로의 unboxing이 실제로 느리지 만 일관성이 있음을 언급 한 value type case 이외의 성능에 대해서는 언급하지 않습니다.
Naasking의 답변에 따라 is-and-cast 또는 is-and-and-as는 아래 코드에서 볼 수 있듯이 최신 JIT를 사용하여 null 검사만큼 빠릅니다.
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 안에 실행됩니다. 두 가지주의 사항 :
- 그들 사이에는 큰 차이가 없습니다. (사실, 상황이 거기로 플러스 null이 검사는 확실히있는에 있다 . 느린가 봉인 클래스이기 때문에 위의 코드는 실제로 타입 체크 쉽게, 만약 당신이 인터페이스에있는 거 검사, 균형 팁 약간 as-plus-null-check를 선호합니다.)
- 그들은 모두 엄청나게 빠릅니다. 이것은 단순히 되지 않습니다 당신이 정말로하지 않을 않는 코드에서 병목 아무것도 나중에 값을.
따라서 성능에 대해 걱정하지 마십시오. 정확성과 일관성에 대해 걱정합시다.
변수를 다룰 때 is-and-cast (또는 is-and-as)는 모두 안전하지 않다고 주장합니다. 테스트와 캐스트 사이의 다른 스레드로 인해 참조되는 값의 유형이 변경 될 수 있기 때문입니다. 이는 매우 드문 상황이지만 일관성있게 사용할 수있는 규칙이 있습니다.
또한 null 검사는 더 나은 우려 분리를 제공합니다. 변환을 시도하는 문장과 결과를 사용하는 문장이 있습니다. is-and-cast 또는 is-and-as는 테스트를 수행 한 다음 값을 변환하려는 또 다른 시도를 수행 합니다.
다른 말로하면, 누군가는 것 이제까지 쓰기 :
int value;
if (int.TryParse(text, out value))
{
value = int.Parse(text);
// Use value
}
그것은 다소 저렴한 방식이지만, 캐스트와 캐스트가하는 일입니다.