'is'대 null 검사로 시도 캐스트
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
참고 URL : https://stackoverflow.com/questions/13405714/is-versus-try-cast-with-null-check
'IT' 카테고리의 다른 글
운영 변환 라이브러리? (0) | 2020.08.19 |
---|---|
isset () 및 empty ()-사용할 사항 (0) | 2020.08.19 |
대체 바이너리 파일에 쓰는 방법? (0) | 2020.08.19 |
“: nothing”옵션은 더 이상 사용하지 않을 것입니다. (0) | 2020.08.19 |
편집하고 계속하기 : "다음 경우에는 변경이 허용되지 않습니다." (0) | 2020.08.19 |