Resharper가 이것을 돌리라고 제안하는 것을 발견했습니다.
if (myObj.myProp is MyType)
{
...
}
이것으로 :
var myObjRef = myObj.myProp as MyType;
if (myObjRef != null)
{
...
}
왜 이러한 변화를 제안합니까? 저는 Resharper가 최적화 변경과 코드 감소 변경을 제안하는 데 익숙하지만, 이것은 내 단일 문장을 두 줄로 바꾸고 싶은 것처럼 느껴집니다.
MSDN 에 따르면 :
은 이다 발현 다음 두 조건이 모두 충족 될 경우는 true로 평가
식이 null이 아닙니다. expression은 유형 으로 캐스트 될 수 있습니다 . 즉, 양식의 캐스트 표현식은
(type)(expression)
예외를 발생시키지 않고 완료됩니다.
is
null 검사를 위해 다른 지역 변수를 명시 적으로 만들 필요없이 한 줄에 정확히 동일한 검사를 수행 하지 않거나 잘못 읽었 습니까?
답변
캐스트가 하나뿐이기 때문입니다. 이것을 비교하십시오 :
if (myObj.myProp is MyType) // cast #1
{
var myObjRef = (MyType)myObj.myProp; // needs to be cast a second time
// before using it as a MyType
...
}
이에:
var myObjRef = myObj.myProp as MyType; // only one cast
if (myObjRef != null)
{
// myObjRef is already MyType and doesn't need to be cast again
...
}
C # 7.0은 패턴 일치를 사용하여보다 간결한 구문을 지원합니다 .
if (myObj.myProp is MyType myObjRef)
{
...
}
답변
가장 좋은 방법은 다음과 같은 패턴 일치를 사용하는 것입니다.
if (value is MyType casted){
//Code with casted as MyType
//value is still the same
}
//Note: casted can be used outside (after) the 'if' scope, too
답변
실제로 벨트 아래에서 일어나는 일에 대한 정보는 아직 없습니다. 이 예를 살펴보십시오.
object o = "test";
if (o is string)
{
var x = (string) o;
}
이것은 다음 IL로 변환됩니다.
IL_0000: nop
IL_0001: ldstr "test"
IL_0006: stloc.0 // o
IL_0007: ldloc.0 // o
IL_0008: isinst System.String
IL_000D: ldnull
IL_000E: cgt.un
IL_0010: stloc.1
IL_0011: ldloc.1
IL_0012: brfalse.s IL_001D
IL_0014: nop
IL_0015: ldloc.0 // o
IL_0016: castclass System.String
IL_001B: stloc.2 // x
IL_001C: nop
IL_001D: ret
여기서 중요한 것은 isinst
및 castclass
호출입니다. 둘 다 상대적으로 비쌉니다. 그것을 대안과 비교하면 isinst
확인 만 수행한다는 것을 알 수 있습니다 .
object o = "test";
var oAsString = o as string;
if (oAsString != null)
{
}
IL_0000: nop
IL_0001: ldstr "test"
IL_0006: stloc.0 // o
IL_0007: ldloc.0 // o
IL_0008: isinst System.String
IL_000D: stloc.1 // oAsString
IL_000E: ldloc.1 // oAsString
IL_000F: ldnull
IL_0010: cgt.un
IL_0012: stloc.2
IL_0013: ldloc.2
IL_0014: brfalse.s IL_0018
IL_0016: nop
IL_0017: nop
IL_0018: ret
또한 언급 할 가치가있는 것은 값 유형이 다음 unbox.any
대신 사용 한다는 것입니다 castclass
.
object o = 5;
if (o is int)
{
var x = (int)o;
}
IL_0000: nop
IL_0001: ldc.i4.5
IL_0002: box System.Int32
IL_0007: stloc.0 // o
IL_0008: ldloc.0 // o
IL_0009: isinst System.Int32
IL_000E: ldnull
IL_000F: cgt.un
IL_0011: stloc.1
IL_0012: ldloc.1
IL_0013: brfalse.s IL_001E
IL_0015: nop
IL_0016: ldloc.0 // o
IL_0017: unbox.any System.Int32
IL_001C: stloc.2 // x
IL_001D: nop
IL_001E: ret
그러나 이것이 반드시 여기에서 볼 수있는 것처럼 더 빠른 결과로 변환되는 것은 아닙니다 . 캐스트가 될하는 데 사용하지만, 최대한 빨리 수행 할 것 같습니다 :하지만 그 질문은 질문 이후 개선되었을 것 같다 as
및 linq
현재 약 3 배 빠른 속도입니다.
답변
Resharper 경고 :
"Type check and direct cast can be replaced with try cast and check for null"
둘 다 작동하며 코드가 더 잘 맞는지에 따라 다릅니다. 제 경우에는 그 경고를 무시합니다.
//1st way is n+1 times of casting
if (x is A) ((A)x).Run();
else if (x is B) ((B)x).Run();
else if (x is C) ((C)x).Run();
else if (x is D) ((D)x).Run();
//...
else if (x is N) ((N)x).Run();
//...
else if (x is Z) ((Z)x).Run();
//2nd way is z times of casting
var a = x as Type A;
var b = x as Type B;
var c = x as Type C;
//..
var n = x as Type N;
//..
var z = x as Type Z;
if (a != null) a.Run();
elseif (b != null) b.Run();
elseif (c != null) c.Run();
...
elseif (n != null) n.Run();
...
elseif (x != null) x.Run();
내 코드에서 두 번째 방법은 더 길고 성능이 떨어집니다.
답변
나에게 이것은 그 유형이 될 가능성이 무엇인지에 달려 있습니다. 개체가 대부분의 경우 해당 유형의 경우 전면 캐스트를 수행하는 것이 확실히 더 효율적입니다. 그 유형이 가끔씩 만 발생한다면 우선 is로 확인하는 것이 더 최적 일 수 있습니다.
지역 변수를 만드는 비용은 유형 검사 비용에 비해 매우 미미합니다.
가독성과 범위는 일반적으로 나에게 더 중요한 요소입니다. 저는 ReSharper에 동의하지 않으며 그 이유만으로 “is”연산자를 사용합니다. 이것이 진정한 병목이라면 나중에 최적화하십시오.
( myObj.myProp is MyType
이 기능에서 한 번만 사용한다고 가정합니다 )
답변
두 번째 변경 사항도 제안해야합니다.
(MyType)myObj.myProp
으로
myObjRef
이렇게하면 원래 코드와 비교하여 속성 액세스 및 캐스트가 절약됩니다. 그러나로 변경 한 후에 만 가능 is
합니다 as
.
답변
이것은 myObjRef 인 myObj.myProp의 강력한 형식 버전을 만드는 것입니다. 그런 다음 블록에서이 값을 참조 할 때와 캐스트를 수행해야 할 때 사용해야합니다.
예를 들면 다음과 같습니다.
myObjRef.SomeProperty
이것보다 낫다 :
((MyType)myObj.myProp).SomeProperty