CLR에서 'as'키워드를 사용하여 캐스팅
인터페이스를 프로그래밍 할 때 많은 캐스팅 또는 객체 유형 변환을하고 있음을 발견했습니다.
이 두 가지 변환 방법에는 차이가 있습니까? 그렇다면 비용 차이가 있습니까? 아니면 이것이 내 프로그램에 어떤 영향을 줍니까?
public interface IMyInterface
{
void AMethod();
}
public class MyClass : IMyInterface
{
public void AMethod()
{
//Do work
}
// Other helper methods....
}
public class Implementation
{
IMyInterface _MyObj;
MyClass _myCls1;
MyClass _myCls2;
public Implementation()
{
_MyObj = new MyClass();
// What is the difference here:
_myCls1 = (MyClass)_MyObj;
_myCls2 = (_MyObj as MyClass);
}
}
또한 "일반적으로"선호되는 방법은 무엇입니까?
이 줄 아래의 답변은 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
}
그것은 다소 저렴한 방식이지만, 캐스트와 캐스트가하는 일입니다.
캐스트 할 수없는 경우 "as" 는 NULL을 리턴합니다.
전에 캐스팅 하면 예외가 발생합니다.
성능을 위해 예외를 발생시키는 것은 일반적으로 시간이 더 걸립니다.
IL 비교와 함께 또 다른 대답이 있습니다. 수업을 고려하십시오.
public class MyClass
{
public static void Main()
{
// Call the 2 methods
}
public void DirectCast(Object obj)
{
if ( obj is MyClass)
{
MyClass myclass = (MyClass) obj;
Console.WriteLine(obj);
}
}
public void UsesAs(object obj)
{
MyClass myclass = obj as MyClass;
if (myclass != null)
{
Console.WriteLine(obj);
}
}
}
이제 각 방법이 생성하는 IL을 살펴보십시오. op 코드가 아무 의미가 없더라도 DirectCast 메서드에서 isinst가 호출되고 castclass가 발생한다는 한 가지 큰 차이점을 알 수 있습니다. 기본적으로 하나 대신 두 개의 호출.
.method public hidebysig instance void DirectCast(object obj) cil managed
{
// Code size 22 (0x16)
.maxstack 8
IL_0000: ldarg.1
IL_0001: isinst MyClass
IL_0006: brfalse.s IL_0015
IL_0008: ldarg.1
IL_0009: castclass MyClass
IL_000e: pop
IL_000f: ldarg.1
IL_0010: call void [mscorlib]System.Console::WriteLine(object)
IL_0015: ret
} // end of method MyClass::DirectCast
.method public hidebysig instance void UsesAs(object obj) cil managed
{
// Code size 17 (0x11)
.maxstack 1
.locals init (class MyClass V_0)
IL_0000: ldarg.1
IL_0001: isinst MyClass
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: brfalse.s IL_0010
IL_000a: ldarg.1
IL_000b: call void [mscorlib]System.Console::WriteLine(object)
IL_0010: ret
} // end of method MyClass::UsesAs
isinst 키워드와 캐스트 클래스
이 블로그 게시물 은 두 가지 방법을 적절히 비교합니다. 그의 요약은 다음과 같습니다.
- 직접 비교에서 isinst는 캐스트 클래스보다 빠릅니다 (약간만)
- 변환이 성공적으로 이루어 졌는지 확인해야 할 때 isinst는 캐스트 클래스보다 훨씬 빠릅니다.
- isinst와 castclass의 조합은 가장 빠른 "안전한"변환보다 훨씬 느리므로 (12 % 이상 느리게) 사용해서는 안됩니다.
나는 개인적으로 항상 As를 사용합니다. 읽기 쉽고 .NET 개발 팀 (또는 Jeffrey Richter)이 권장하기 때문입니다.
둘 사이의 더 미묘한 차이점 중 하나는 캐스트 연산자가 포함 된 경우 "as"키워드를 캐스트에 사용할 수 없다는 것입니다.
public class Foo
{
public string Value;
public static explicit operator string(Foo f)
{
return f.Value;
}
}
public class Example
{
public void Convert()
{
var f = new Foo();
f.Value = "abc";
string cast = (string)f;
string tryCast = f as string;
}
}
"as"키워드는 캐스트 연산자를 고려하지 않기 때문에 마지막 행에서 컴파일되지 않습니다 (이전 버전에서는 그렇게 생각했지만). 라인 string cast = (string)f;
은 잘 작동합니다.
등 이 전환 복귀 수행 할 수없는 경우 결코 예외가 발생하지 널을 (대신 으로 참조 형식에서만 동작한다). 따라서 as를 사용 하는 것은 기본적으로
_myCls2 = _myObj is MyClass ? (MyClass)_myObj : null;
반면 C 스타일 캐스트는 변환이 불가능할 때 예외를 발생시킵니다.
실제로 귀하의 질문에 대한 답변이 아니라 중요한 생각이 중요하다고 생각합니다.
인터페이스로 프로그래밍하는 경우 캐스팅 할 필요가 없습니다. 바라건대이 캐스트는 매우 드 rare니다. 그렇지 않은 경우 일부 인터페이스를 다시 생각해야합니다.
Jon Skeet의 조언을 무시하십시오. 테스트 및 캐스트 패턴을 피하십시오.
if (randomObject is TargetType)
{
TargetType foo = randomObject as TargetType;
// Do something with foo
}
이것은 캐스트 및 널 테스트보다 비용이 많이 든다는 아이디어는 신화입니다 .
TargetType convertedRandomObject = randomObject as TargetType;
if (convertedRandomObject != null)
{
// Do stuff with convertedRandomObject
}
작동하지 않는 미세 최적화입니다. 나는 도망 진짜 테스트를 하고, 테스트 및 캐스트 실제로 빠른 캐스트 - 및 - 널 비교보다, 당신은 캐스트해야하는 경우 외부 범위에서 널 참조를 가질 가능성이 없기 때문에 너무 더 안전 불합격.
테스트 및 캐스트가 더 빠르거나 적어도 느리지 않은 이유를 원한다면 간단하고 복잡한 이유가 있습니다.
단순함 : 순진한 컴파일러조차도 테스트 및 캐스트와 같은 두 가지 유사한 작업을 단일 테스트 및 분기로 통합합니다. cast-and-null-test는 두 가지 테스트와 브랜치를 강제 할 수 있습니다. 하나는 유형 테스트 용이고 하나는 실패시 null로, 하나는 null 검사 자체입니다. 최소한 단일 테스트 및 분기에 모두 최적화되므로 테스트 및 캐스트는 캐스트 앤 널 테스트보다 느리거나 빠르지 않습니다.
복잡함 : 테스트 및 캐스트가 더 빠른 이유 : 캐스트 앤 널 테스트는 컴파일러가 라이브를 추적해야하는 외부 범위에 다른 변수를 도입하며 제어가 얼마나 복잡한 지에 따라 해당 변수를 최적화하지 못할 수 있습니다. 흐름입니다. 반대로, 테스트 앤 캐스트는 범위가 한정된 범위에서만 새 변수를 도입하므로 컴파일러는 범위가 종료 된 후 변수가 종료되었음을 알 수 있으므로 레지스터 할당을보다 잘 최적화 할 수 있습니다.
따라서이 "캐스트 앤 널 테스트가 테스트 앤 캐스트보다 낫다"는 조언 DIE를 보내 주시기 바랍니다. 부디. 테스트 앤 캐스트는 더 안전하고 빠릅니다.
캐스트가 실패하면 'as'키워드에서 예외가 발생하지 않습니다. 대신 변수를 널 (또는 값 유형의 기본값)로 설정합니다.
이것은 질문에 대한 답변이 아니라 질문 코드 예제에 대한 의견입니다.
일반적으로 IMyInterface에서 MyClass로 Object를 캐스트 할 필요는 없습니다. 인터페이스의 가장 큰 장점은 인터페이스를 구현하는 입력으로 객체를 가져 오면 어떤 종류의 객체를 가져올 지 신경 쓰지 않아도된다는 것입니다.
IMyInterface를 MyClass로 캐스팅하면 이미 MyClass 유형의 객체를 가져오고 IMyInterface를 사용하는 것이 의미가 없다고 가정하는 것보다 IMyInterface를 구현하는 다른 클래스에 코드를 공급하면 코드가 손상되므로 ...
이제 내 충고 : 인터페이스가 잘 설계되면 많은 유형 캐스팅을 피할 수 있습니다.
as
연산자는 과부하가 될 수없고, 참조 형식에 사용될 수 있고, 반환 null
동작이 실패하는 경우. 예외는 발생하지 않습니다.
캐스팅은 호환 가능한 모든 유형에서 사용될 수 있으며 오버로드 될 수 있으며 작업이 실패하면 예외가 발생합니다.
사용할 선택은 상황에 따라 다릅니다. 기본적으로 실패한 전환에 대해 예외를 발생 시킬지 여부는 중요합니다.
내 대답은 유형을 확인하지 않고 캐스팅 후 null을 확인하지 않는 경우에만 속도에 관한 것입니다. Jon Skeet의 코드에 두 가지 테스트를 추가했습니다.
using System;
using System.Diagnostics;
class Test
{
const int Size = 30000000;
static void Main()
{
object[] values = new object[Size];
for (int i = 0; i < Size; i++)
{
values[i] = "x";
}
FindLengthWithIsAndCast(values);
FindLengthWithIsAndAs(values);
FindLengthWithAsAndNullCheck(values);
FindLengthWithCast(values);
FindLengthWithAs(values);
Console.ReadLine();
}
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);
}
static void FindLengthWithCast(object[] values)
{
Stopwatch sw = Stopwatch.StartNew();
int len = 0;
foreach (object o in values)
{
string a = (string)o;
len += a.Length;
}
sw.Stop();
Console.WriteLine("Cast: {0} : {1}", len,
(long)sw.ElapsedMilliseconds);
}
static void FindLengthWithAs(object[] values)
{
Stopwatch sw = Stopwatch.StartNew();
int len = 0;
foreach (object o in values)
{
string a = o as string;
len += a.Length;
}
sw.Stop();
Console.WriteLine("As: {0} : {1}", len,
(long)sw.ElapsedMilliseconds);
}
}
결과:
Is and Cast: 30000000 : 88
Is and As: 30000000 : 93
As and null check: 30000000 : 56
Cast: 30000000 : 66
As: 30000000 : 46
이 모든 것이 매우 빠르기 때문에 (내가했던 것처럼) 속도에 집중하려고하지 마십시오.
여기에 이미 노출 된 모든 것 외에도 명시 적 캐스팅 사이에서 주목할 가치가 있다고 생각하는 실제적인 차이점을 발견했습니다
var x = (T) ...
as
연산자 사용 대 .
예를 들면 다음과 같습니다.
class Program
{
static void Main(string[] args)
{
Console.WriteLine(GenericCaster<string>(12345));
Console.WriteLine(GenericCaster<object>(new { a = 100, b = "string" }) ?? "null");
Console.WriteLine(GenericCaster<double>(20.4));
//prints:
//12345
//null
//20.4
Console.WriteLine(GenericCaster2<string>(12345));
Console.WriteLine(GenericCaster2<object>(new { a = 100, b = "string" }) ?? "null");
//will not compile -> 20.4 does not comply due to the type constraint "T : class"
//Console.WriteLine(GenericCaster2<double>(20.4));
}
static T GenericCaster<T>(object value, T defaultValue = default(T))
{
T castedValue;
try
{
castedValue = (T) Convert.ChangeType(value, typeof(T));
}
catch (Exception)
{
castedValue = defaultValue;
}
return castedValue;
}
static T GenericCaster2<T>(object value, T defaultValue = default(T)) where T : class
{
T castedValue;
try
{
castedValue = Convert.ChangeType(value, typeof(T)) as T;
}
catch (Exception)
{
castedValue = defaultValue;
}
return castedValue;
}
}
결론 : GenericCaster2는 구조체 유형에서 작동하지 않습니다. GenericCaster가 할 것입니다.
.NET Framework 4.X를 대상으로하는 Office PIA를 사용하는 경우 as 키워드를 사용해야합니다 . 그렇지 않으면 컴파일되지 않습니다.
Microsoft.Office.Interop.Outlook.Application o = new Microsoft.Office.Interop.Outlook.Application();
Microsoft.Office.Interop.Outlook.MailItem m = o.CreateItem(Microsoft.Office.Interop.Outlook.OlItemType.olMailItem) as Microsoft.Office.Interop.Outlook.MailItem;
주조는 .NET 2.0 불구 대상으로 할 때 OK입니다 :
Microsoft.Office.Interop.Outlook.MailItem m = (Microsoft.Office.Interop.Outlook.MailItem)o.CreateItem(Microsoft.Office.Interop.Outlook.OlItemType.olMailItem);
.NET 4.X를 타겟팅 할 때 오류는 다음과 같습니다.
오류 CS0656 : 누락 된 컴파일러 필수 멤버 'Microsoft.CSharp.RuntimeBinder.Binder.Convert'
오류 CS0656 : 누락 된 컴파일러 필수 멤버 'Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create'
as
키워드는 변환이 실패 할 경우 예외를 발생시키지 않습니다 주요 차이와 호환 참조 유형 간의 명시 적 캐스트와 동일하게 작동합니다. 대신 대상 변수에 널값을 생성합니다. 예외는 성능면에서 매우 비싸기 때문에 훨씬 나은 캐스팅 방법으로 간주됩니다.
당신이 선택하는 것은 필요한 것에 달려 있습니다. 나는 명시 적 캐스팅을 선호합니다
IMyInterface = (IMyInterface)someobj;
IMyInterface 유형으로 객체를 가져와야하지만 그렇지 않은 경우-확실히 문제입니다. 부작용을 수정하는 대신 정확한 오류가 수정되므로 가능한 빨리 오류를 얻는 것이 좋습니다.
그러나 object
매개 변수로 허용 되는 메서드를 처리 하는 경우 코드를 실행하기 전에 정확한 유형을 확인해야합니다. 이러한 경우에는 as
피할 수 있으므로 유용합니다 InvalidCastException
.
"as"를 사용한 후 null을 확인 하시겠습니까? 아니면 앱에서 예외를 발생 시키길 원하십니까?
경험적으로 볼 때 변수가 항상 캐스트를 사용할 때 예상되는 유형이 될 것으로 기대하는 경우입니다. 변수가 내가 원하는 것으로 캐스팅되지 않고 as를 사용하여 null을 처리 할 준비가되면 as를 사용합니다.
다음 링크를 살펴보십시오.
- http://gen5.info/q/2008/06/13/prefix-casting-versus-as-casting-in-c/
- http://www.codeproject.com/Articles/8052/Type-casting-impact-over-execution-performance-in
세부 사항과 성능 테스트를 보여줍니다.
OP의 문제는 특정 캐스팅 상황으로 제한됩니다. 제목은 훨씬 더 많은 상황을 다룹니다.
현재 내가 생각할 수있는 모든 관련 주조 상황에 대한 개요는 다음과 같습니다.
private class CBase
{
}
private class CInherited : CBase
{
}
private enum EnumTest
{
zero,
one,
two
}
private static void Main (string[] args)
{
//########## classes ##########
// object creation, implicit cast to object
object oBase = new CBase ();
object oInherited = new CInherited ();
CBase oBase2 = null;
CInherited oInherited2 = null;
bool bCanCast = false;
// explicit cast using "()"
oBase2 = (CBase)oBase; // works
oBase2 = (CBase)oInherited; // works
//oInherited2 = (CInherited)oBase; System.InvalidCastException
oInherited2 = (CInherited)oInherited; // works
// explicit cast using "as"
oBase2 = oBase as CBase;
oBase2 = oInherited as CBase;
oInherited2 = oBase as CInherited; // returns null, equals C++/CLI "dynamic_cast"
oInherited2 = oInherited as CInherited;
// testing with Type.IsAssignableFrom(), results (of course) equal the results of the cast operations
bCanCast = typeof (CBase).IsAssignableFrom (oBase.GetType ()); // true
bCanCast = typeof (CBase).IsAssignableFrom (oInherited.GetType ()); // true
bCanCast = typeof (CInherited).IsAssignableFrom (oBase.GetType ()); // false
bCanCast = typeof (CInherited).IsAssignableFrom (oInherited.GetType ()); // true
//########## value types ##########
int iValue = 2;
double dValue = 1.1;
EnumTest enValue = EnumTest.two;
// implicit cast, explicit cast using "()"
int iValue2 = iValue; // no cast
double dValue2 = iValue; // implicit conversion
EnumTest enValue2 = (EnumTest)iValue; // conversion by explicit cast. underlying type of EnumTest is int, but explicit cast needed (error CS0266: Cannot implicitly convert type 'int' to 'test01.Program.EnumTest')
iValue2 = (int)dValue; // conversion by explicit cast. implicit cast not possible (error CS0266: Cannot implicitly convert type 'double' to 'int')
dValue2 = dValue;
enValue2 = (EnumTest)dValue; // underlying type is int, so "1.1" beomces "1" and then "one"
iValue2 = (int)enValue;
dValue2 = (double)enValue;
enValue2 = enValue; // no cast
// explicit cast using "as"
// iValue2 = iValue as int; error CS0077: The as operator must be used with a reference type or nullable type
}
참고 URL : https://stackoverflow.com/questions/496096/casting-vs-using-the-as-keyword-in-the-clr
'Programming' 카테고리의 다른 글
float와 double의 차이점은 무엇입니까? (0) | 2020.02.26 |
---|---|
GitHub 프로젝트에서 README와 README.md의 차이점은 무엇입니까? (0) | 2020.02.26 |
IEnumerable에 항목을 추가하는 방법 (0) | 2020.02.26 |
기능이 조기에 종료 되었습니까? (0) | 2020.02.26 |
STA와 MTA를 설명해 주시겠습니까? (0) | 2020.02.25 |