10 변환
10.1 일반
변환으로 인해 식이 특정 형식으로 변환되거나 특정 형식으로 처리됩니다. 이전의 경우 변환에는 표현 변경이 포함될 수 있습니다. 변환은 암시적 또는 명시적일 수 있으며 명시적 캐스트가 필요한지 여부를 결정합니다.
예: 예를 들어 형식에서 형식
int
long
으로의 변환은 암시적이므로 형식int
의 식은 암시적으로 형식long
으로 처리될 수 있습니다. 형식에서 형식long
int
으로의 반대 변환은 명시적이므로 명시적 캐스트가 필요합니다.int a = 123; long b = a; // implicit conversion from int to long int c = (int) b; // explicit conversion from long to int
끝 예제
일부 변환은 언어로 정의됩니다. 프로그램은 자체 변환을 정의할 수도 있습니다(§10.5).
언어의 일부 변환은 식에서 형식으로 정의되고 다른 변환은 형식에서 형식으로 정의됩니다. 형식에서의 변환은 해당 형식이 있는 모든 식에 적용됩니다.
예제:
enum Color { Red, Blue, Green } // The expression 0 converts implicitly to enum types Color c0 = 0; // Other int expressions need explicit conversion Color c1 = (Color)1; // Conversion from null expression (no type) to string string x = null; // Conversion from lambda expression to delegate type Func<int, int> square = x => x * x;
끝 예제
10.2 암시적 변환
10.2.1 일반
다음 변환은 암시적 변환으로 분류됩니다.
- ID 변환(§10.2.2)
- 암시적 숫자 변환(§10.2.3)
- 암시적 열거형 변환(§10.2.4)
- 암시적 보간된 문자열 변환(§10.2.5)
- 암시적 참조 변환(§10.2.8)
- Boxing 변환(§10.2.9)
- 암시적 동적 변환(§10.2.10)
- 암시적 형식 매개 변수 변환(§10.2.12)
- 암시적 상수 식 변환(§10.2.11)
- 사용자 정의(해제된 경우 포함) 암시적 변환(§10.2.14)
- 익명 함수 변환(§10.2.15)
- 메서드 그룹 변환(§10.2.15)
- Null 리터럴 변환(§10.2.7)
- 암시적 nullable 변환(§10.2.6)
- 암시적 튜플 변환(§10.2.13)
- 기본 리터럴 변환(§10.2.16)
- 암시적 throw 변환(§10.2.17)
함수 멤버 호출(§12.6.6), 캐스트 식(§12.9.7) 및 할당(§12.21)을 비롯한 다양한 상황에서 암시적 변환이 발생할 수 있습니다.
미리 정의된 암시적 변환은 항상 성공하며 예외가 throw되지 않습니다.
참고: 올바르게 디자인된 사용자 정의 암시적 변환도 이러한 특성을 나타내야 합니다. 끝 메모
변환을 위해 형식 object
및 dynamic
ID 변환 가능(§10.2.2)입니다.
그러나 동적 변환(§10.2.10)은 형식 dynamic
의 식(§8.2.4)에만 적용됩니다.
10.2.2 ID 변환
ID 변환은 모든 형식에서 동일한 형식 또는 런타임 시 동일한 형식으로 변환됩니다. 이 변환이 존재하는 이유 중 하나는 형식 또는 형식 T
T
의 식을 자체로 변환 T
할 수 있기 때문입니다. 다음과 같은 ID 변환이 존재합니다.
- 사이
T
및T
모든 형식T
에 대해 . - 참조 형식 간
T
및T?
모든 참조 형식T
에 대해 . - 사이
object
및 .dynamic
- 해당하는 요소 형식의 각 쌍 간에 ID 변환이 존재하는 경우 동일한 아레티를 가진 모든 튜플 형식과 해당 생성된
ValueTuple<...>
형식 사이에 있습니다. - 동일한 제네릭 형식에서 생성된 형식 간에 각 해당 형식 인수 간에 ID 변환이 존재합니다.
예제: 다음은 세 번째 규칙의 재귀 특성을 보여 줍니다.
(int a , string b) t1 = (1, "two"); (int c, string d) t2 = (3, "four"); // Identity conversions exist between // the types of t1, t2, and t3. var t3 = (5, "six"); t3 = t2; t2 = t1; var t4 = (t1, 7); var t5 = (t2, 8); // Identity conversions exist between // the types of t4, t5, and t6. var t6 =((8, "eight"), 9); t6 = t5; t5 = t4;
튜플
t1
t2
의 형식과t3
모두 두 개의 요소가int
있습니다. 그 뒤에는 .가string
있습니다. 튜플 요소 형식은 튜플에서와 같이t4
,t5
및t6
. 중첩된 튜플을 포함하여 해당 요소 형식의 각 쌍 간에 ID 변환이 존재하므로 튜플 형식과t4
튜플 형식 간에 ID 변환이 존재합니다.t5
t6
끝 예제
모든 ID 변환은 대칭입니다. ID 변환이 있는 T₁
T₂
경우 ID 변환이 존재합니다 T₂
T₁
. 두 형식 사이에 ID 변환이 있는 경우 두 형식은 ID 변환이 가능 합니다.
대부분의 경우 ID 변환은 런타임에 영향을 주지 않습니다. 그러나 부동 소수점 연산은 해당 형식(§8.3.7)에 의해 규정된 것보다 높은 정밀도로 수행될 수 있으므로 결과를 할당하면 정밀도가 손실될 수 있으며 명시적 캐스트는 형식(§12.9.7)에 의해 규정된 정밀도를 줄이도록 보장됩니다.
10.2.3 암시적 숫자 변환
암시적 숫자 변환은 다음과 같습니다.
- From to
sbyte
short
,int
,long
,float
,double
또는decimal
. - From to
byte
short
,ushort
, ,int
,uint
long
,ulong
,float
,double
또는decimal
. - From to
short
int
,long
,float
,double
또는decimal
. - From to
ushort
int
,uint
, ,long
ulong
,float
,double
또는decimal
. - From to
int
long
,float
,double
또는decimal
. - From to
uint
long
,ulong
,float
,double
또는decimal
. - From to
long
float
,double
또는decimal
. - From to
ulong
float
,double
또는decimal
. - From to
char
ushort
,int
, ,uint
long
,ulong
,float
,double
또는decimal
. -
float
~double
입니다.
또는 그 안 int
uint
long
ulong
float
long
을 오가 ulong
는 double
변환으로 인해 정밀도가 손실될 수 있지만 크기가 손실되지는 않습니다. 다른 암시적 숫자 변환 시에는 정보 손실이 없습니다.
형식에 char
대한 미리 정의된 암시적 변환이 없으므로 다른 정수 계열 형식의 값은 자동으로 형식으로 char
변환되지 않습니다.
10.2.4 암시적 열거형 변환
암시적 열거형 변환을 사용하면 정수 형식이 있는 constant_expression(§12.23)와 값 0을 모든 enum_type 변환하고 기본 형식이 enum_type nullable_value_type 변환할 수 있습니다. 후자의 경우 변환은 기본 enum_type 변환하고 결과를 래핑하여 평가됩니다(§8.3.12).
10.2.5 암시적 보간된 문자열 변환
암시적 보간된 문자열 변환을 사용하면 interpolated_string_expression(§12.8.3)를 변환하거나 System.IFormattable
(구현하는) 변환 System.FormattableString
할 수 있습니다System.IFormattable
.
이 변환을 적용하면 보간된 문자열에서 문자열 값이 구성되지 않습니다. 대신 §12.8.3System.FormattableString
자세히 설명된 대로 인스턴스 가 만들어집니다.
10.2.6 암시적 nullable 변환
암시적 nullable 변환은 암시적 미리 정의된 변환에서 파생된 null 허용 변환(§10.6.1)입니다.
10.2.7 Null 리터럴 변환
암시적 변환은 리터럴에서 null
모든 참조 형식 또는 nullable 값 형식으로 존재합니다. 이 변환은 대상 형식이 참조 형식이거나 지정된 nullable 값 형식의 null 값(§8.3.12)인 경우 null 참조를 생성합니다.
10.2.8 암시적 참조 변환
암시적 참조 변환은 다음과 같습니다.
- 모든 reference_type 및 .
object
dynamic
- 모든 class_type
S
class_type .T
S
T
- 모든
S
T
interface_type 제공된S
구현으로.T
- 모든
T
S
T
interface_type . - 요소 형식이 있는 array_type
S
요소 형식Sᵢ
이 있는 array_typeT
Tᵢ
다음이 모두 true인 경우-
S
요소T
형식에서만 다릅니다. 즉,S
T
동일한 수의 차원이 있습니다. - 암시적 참조 변환이 있습니다
Sᵢ
Tᵢ
.
-
- 암시적 ID 또는 참조 변환이 있는 경우 1차원 배열 형식
S[]
System.Collections.Generic.IList<T>
System.Collections.Generic.IReadOnlyList<T>
에서S
, 및 해당 기본 인터페이스로 변환합니다.T
- 구현하는 인터페이스
System.Array
. - 구현하는 모든 delegate_type
System.Delegate
및 인터페이스로. - null 리터럴(§6.4.5.7)에서 참조 형식으로.
- 암시적 ID 또는 reference_type
T
- 인터페이스 또는 대리자 형식으로의 암시적 ID 또는 참조 변환이 있고 분산 컨버터블(
T
)T₀
인 경우 인터페이스 또는 대리자 형식T₀
으로의 reference_type.T
- 참조 형식으로 알려진 형식 매개 변수와 관련된 암시적 변환입니다. 형식 매개 변수와 관련된 암시적 변환에 대한 자세한 내용은 §10.2.12를 참조하세요.
암시적 참조 변환은 항상 성공하는 것으로 입증될 수 있는 reference_type간의 변환이므로 런타임에 검사가 필요하지 않습니다.
암시적 또는 명시적 참조 변환은 변환되는 개체의 참조 ID를 변경하지 않습니다.
참고: 즉, 참조 변환은 참조 형식을 변경할 수 있지만 참조되는 개체의 형식이나 값은 변경되지 않습니다. 끝 메모
10.2.9 Boxing 변환
boxing 변환을 사용하면 value_type 암시적으로 reference_type 변환할 수 있습니다. 다음과 같은 boxing 변환이 있습니다.
- 모든 value_type 형식
object
으로. - 모든 value_type 형식
System.ValueType
으로. - 모든 enum_type 형식
System.Enum
으로. - 모든 non_nullable_value_type non_nullable_value_type 구현된 interface_type.
- non_nullable_value_type
I₀
I₀
I
- non_nullable_value_type
I₀
I
non_nullable_value_type. - 모든 nullable_value_type nullable_value_type 기본 형식에서 reference_type boxing 변환이 있는 reference_type.
- 참조 형식으로 알려져 있지 않은 형식 매개 변수에서 변환이 §10.2.12에서 허용되도록 모든 형식으로 변환합니다.
nullable-value-type이 아닌 값의 Boxing은 개체 인스턴스를 할당하고 해당 인스턴스에 값을 복사하는 것으로 구성됩니다.
nullable_value_type 값을 boxing하면 null 값(false)HasValue
이거나 기본 값의 래핑 해제 및 boxing 결과가 있는 경우 null 참조가 생성됩니다.
참고: boxing 프로세스는 모든 값 형식에 대한 boxing 클래스의 존재 측면에서 상상할 수 있습니다. 예를 들어 boxing 클래스를
struct S
사용하여 인터페이스I
를 구현하는 것이 좋습니다S_Boxing
.interface I { void M(); } struct S : I { public void M() { ... } } sealed class S_Boxing : I { S value; public S_Boxing(S value) { this.value = value; } public void M() { value.M(); } }
이제 형식
v
값S
의 Boxing은 식을new S_Boxing(v)
실행하고 결과 인스턴스를 변환 대상 형식의 값으로 반환하는 것으로 구성됩니다. 따라서 문S s = new S(); object box = s;
다음과 비슷하게 생각할 수 있습니다.
S s = new S(); object box = new S_Boxing(s);
위에서 설명한 상상된 권투 유형은 실제로 존재하지 않습니다. 대신, 형식
S
의 boxed 값에는 런타임 형식S
이 있으며, 오른쪽 피연산자로 값 형식이 있는 연산자를 사용하여is
런타임 형식 확인은 왼쪽 피연산자가 오른쪽 피연산자의 boxed 버전인지 여부를 테스트합니다. 예를 들면 다음과 같습니다.int i = 123; object box = i; if (box is int) { Console.Write("Box contains an int"); }
는 다음을 출력합니다.
Box contains an int
boxing 변환은 boxed되는 값의 복사본을 만드는 것을 의미합니다. 이는 값이 동일한 인스턴스를
object
형식object
으로 변환하는 것과 다릅니다. 예를 들어 다음을 수행합니다.struct Point { public int x, y; public Point(int x, int y) { this.x = x; this.y = y; } } class A { void M() { Point p = new Point(10, 10); object box = p; p.x = 20; Console.Write(((Point)box).x); } }
는 할당
p
box
에서 발생하는 암시적 boxing 작업으로 인해 값이 복사되기 때문에 콘솔에서p
값 10을 출력합니다. 대신 선언되었Point
으면class
동일한 인스턴스를 참조하기 때문에p
box
값 20이 출력됩니다.boxing 클래스의 비유는 권투가 개념적으로 작동하는 방식을 그리는 데 유용한 도구 이상으로 사용되어서는 안됩니다. 이 사양에서 설명하는 동작과 boxing이 정확하게 이러한 방식으로 구현될 때 발생하는 동작 사이에는 미묘한 차이가 많이 있습니다.
끝 메모
10.2.10 암시적 동적 변환
암시적 동적 변환은 동적 형식의 식에서 모든 형식 T
으로 존재합니다. 변환은 동적으로 바인딩 된 §12.3.3입니다. 즉, 식의 런타임 형식에서 암시적 변환을 검색합니다 T
. 변환을 찾을 수 없으면 런타임 예외가 throw됩니다.
이 암시적 변환은 암시적 변환으로 인해 예외가 발생하지 않아야 한다는 충고를 §10.2의 시작 부분에 위반하는 것처럼 보입니다. 그러나 변환 자체가 아니라 예외를 유발하는 변환의 발견 입니다. 런타임 예외의 위험은 동적 바인딩 사용에 내재되어 있습니다. 변환의 동적 바인딩을 원하지 않는 경우 식을 먼저 변환한 object
다음 원하는 형식으로 변환할 수 있습니다.
예제: 다음은 암시적 동적 변환을 보여 줍니다.
object o = "object"; dynamic d = "dynamic"; string s1 = o; // Fails at compile-time – no conversion exists string s2 = d; // Compiles and succeeds at run-time int i = d; // Compiles but fails at run-time – no conversion exists
할당과
s2
i
둘 다 암시적 동적 변환을 사용합니다. 여기서 작업의 바인딩은 런타임까지 일시 중단됩니다. 런타임 시 암시적 변환은 (d
)의string
런타임 형식에서 대상 형식으로 검색됩니다. 변환은 다음으로string
찾을 수 있지만 그렇지 않습니다int
.끝 예제
10.2.11 암시적 상수 식 변환
암시적 상수 식 변환은 다음과 같은 변환을 허용합니다.
- constant_expression 값이 대상 형식의 범위 내에 있는 경우 형식 의 constant_expression
ulong
-
constant_expression 값이 음수가 아니면 형식
long
의ulong
형식으로 변환할 수 있습니다.
10.2.12 형식 매개 변수와 관련된 암시적 변환
참조 형식(§15.2.5)으로 알려진 type_parameter T
경우 다음과 같은 암시적 참조 변환(§10.2.8)이 있습니다.
-
T
유효 기본 클래스부터C
기본 클래스T
C
까지, 그리고T
에서 구현된C
모든 인터페이스로. - 유효 인터페이스 집합
T
의 interface_typeI
T
I
-
T
(§15.2.5T
따라 달라지는U
형식 매개 변수 로 이동합니다.참고:
T
참조 형식으로 알려져 있으므로 범위 내에서T
런타임 형식U
은 컴파일 타임에 참조 형식으로 알려져 있지 않더라도U
항상 참조 형식이 됩니다. 끝 메모 - null 리터럴(§6.4.5.7)에서 T로.
참조 형식 §15.2.5로 알려져 있지 않은T
경우 컴파일 타임에 다음과 같은 T
변환이 boxing 변환(§10.2.9)으로 간주됩니다. 런타임에 값 형식인 경우 T
변환은 boxing 변환으로 실행됩니다. 런타임에 참조 형식인 경우 T
변환은 암시적 참조 변환 또는 ID 변환으로 실행됩니다.
-
T
유효 기본 클래스부터C
기본 클래스T
C
까지, 그리고T
에서 구현된C
모든 인터페이스로.참고:
C
형식 중 하나이거나System.Object
참조System.ValueType
형식System.Enum
T
이라고도 합니다. 끝 메모 - 유효 인터페이스 집합
T
의 interface_typeI
T
I
참조 형식으로 T
경우 제공된 T
형식 매개 변수 U
로 T
의 암시적 변환이 따라 달라집니다U
. 런타임에 값 형식이고 T
참조 형식인 경우 U
변환은 boxing 변환으로 실행됩니다. 런타임에 둘 다 T
값 형식 U
T
인 U
경우 반드시 동일한 형식이며 변환이 수행되지 않습니다. 런타임에 참조 형식인 경우 T
반드시 참조 형식 U
이기도 하며 변환은 암시적 참조 변환 또는 ID 변환(§15.2.5)으로 실행됩니다.
지정된 형식 매개 변수 T
에 대해 다음과 같은 추가 암시적 변환이 있습니다.
-
T
참조 형식S
으로의 암시적 변환이 있고S₀
ID 변환이 있는 경우 참조 형식S₀
으로 변환합니다S
. 런타임에 변환은 변환과 동일한 방식으로S₀
실행됩니다. -
T
인터페이스 형식I
으로의 암시적 변환이 있고I₀
분산 변환이 가능한 경우 인터페이스 형식I₀
으로I
이동합니다(§18.2.3.3). 런타임에 값 형식인 경우T
변환은 boxing 변환으로 실행됩니다. 그렇지 않으면 변환이 암시적 참조 변환 또는 ID 변환으로 실행됩니다.
모든 경우에 규칙은 런타임에 변환이 값 형식에서 참조 형식으로 변환되는 경우에만 변환이 boxing 변환으로 실행되도록 합니다.
10.2.13 암시적 튜플 변환
튜플 식 E
에서 튜플 형식으로의 암시적 변환이 존재하며, 각 요소에서 해당 요소 T
형식 E
T
E
으로 T
암시적 변환이 존재합니다. 변환은 해당 형식의 T
인스턴스를 만들고, 해당하는 튜플 요소 식을 System.ValueTuple<...>
평가하고, 찾은 암시적 변환을 사용하는 해당 요소 형식 E
으로 변환하고, 결과를 사용하여 필드를 초기화하여 각 필드를 왼쪽에서 오른쪽으로 순서대로 초기화하여 수행 T
됩니다.
튜플 식의 요소 이름이 튜플 형식의 해당 요소 이름과 일치하지 않으면 경고가 발생합니다.
예제:
(int, string) t1 = (1, "One"); (byte, string) t2 = (2, null); (int, string) t3 = (null, null); // Error: No conversion (int i, string s) t4 = (i: 4, "Four"); (int i, string) t5 = (x: 5, s: "Five"); // Warning: Names are ignored
요소 식에서 해당 요소 형식으로의
t1
암시적 변환이 존재하기 때문에 ,t2
t4
t5
및 의 선언은 모두 유효합니다. 로의t3
변환null
int
이 없으므로 선언이 잘못되었습니다. 튜플 식의t5
요소 이름이 튜플 형식의 요소 이름과 다르기 때문에 선언으로 인해 경고가 발생합니다.끝 예제
10.2.14 사용자 정의 암시적 변환
사용자 정의 암시적 변환은 선택적 표준 암시적 변환과 사용자 정의 암시적 변환 연산자 실행, 다른 선택적 표준 암시적 변환으로 구성됩니다. 사용자 정의 암시적 변환을 평가하기 위한 정확한 규칙은 §10.5.4에 설명되어 있습니다.
10.2.15 익명 함수 변환 및 메서드 그룹 변환
익명 함수 및 메서드 그룹에는 형식 자체가 없지만 대리자 형식으로 암시적으로 변환될 수 있습니다. 또한 일부 람다 식은 식 트리 형식으로 암시적으로 변환될 수 있습니다. 익명 함수 변환은 §10.7 및 §10.8의 메서드 그룹 변환에 자세히 설명되어 있습니다.
10.2.16 기본 리터럴 변환
암시적 변환은 default_literal(§12.8.21)에서 모든 형식으로 존재합니다. 이 변환은 유추된 형식의 기본값(§9.3)을 생성합니다.
10.2.17 암시적 throw 변환
throw 식에는 형식이 없지만 암시적으로 모든 형식으로 변환될 수 있습니다.
10.3 명시적 변환
10.3.1 일반
다음 변환은 명시적 변환으로 분류됩니다.
- 모든 암시적 변환(§10.2)
- 명시적 숫자 변환(§10.3.2)
- 명시적 열거형 변환(§10.3.3)
- 명시적 nullable 변환(§10.3.4)
- 명시적 튜플 변환(§10.3.6)
- 명시적 참조 변환(§10.3.5)
- 명시적 인터페이스 변환
- 언박싱 변환(§10.3.7)
- 명시적 형식 매개 변수 변환(§10.3.8)
- 사용자 정의 명시적 변환(§10.3.9)
명시적 변환은 캐스트 식(§12.9.7)에서 발생할 수 있습니다.
명시적 변환 집합에는 모든 암시적 변환이 포함됩니다.
참고: 예를 들어 특정 메서드 오버로드를 강제로 선택하기 위해 암시적 ID 변환이 있을 때 명시적 캐스트를 사용할 수 있습니다. 끝 메모
암시적 변환이 아닌 명시적 변환은 항상 성공하는 것으로 입증할 수 없는 변환, 정보를 잃을 가능성이 있는 것으로 알려진 변환, 명시적 표기법과 충분히 다른 형식의 도메인 간 변환입니다.
10.3.2 명시적 숫자 변환
명시적 숫자 변환은 암시적 숫자 변환(§10.2.3)이 아직 없는 다른 numeric_type numeric_type 변환입니다.
- From to
sbyte
byte
,ushort
,uint
,ulong
또는char
. -
byte
으로sbyte
또는char
. - From to
short
sbyte
,byte
,ushort
,uint
,ulong
또는char
. - From to
ushort
sbyte
,byte
,short
또는char
. - From to
int
sbyte
,byte
, ,short
ushort
,uint
,ulong
또는char
. - From to
uint
sbyte
,byte
,short
,ushort
,int
또는char
. - From to
long
sbyte
,byte
, ,short
ushort
,int
,uint
,ulong
또는char
. - From to
ulong
sbyte
,byte
, ,short
ushort
,int
,uint
,long
또는char
. - From to
char
sbyte
,byte
또는short
. - From to
float
sbyte
,byte
, ,short
,ushort
int
,uint
,long
,ulong
,char
또는decimal
. - From to
double
sbyte
,byte
, ,short
,ushort
int
,uint
,long
,ulong
,char
,float
또는decimal
. - From to
decimal
sbyte
,byte
, ,short
,ushort
int
,uint
,long
,ulong
,char
,float
또는double
.
명시적 변환에는 모든 암시적 및 명시적 숫자 변환이 포함되므로 캐스트 식(§12.9.7)을 사용하여 모든 numeric_type 다른 numeric_type 변환할 수 있습니다.
명시적 숫자 변환으로 인해 정보가 손실되거나 예외가 throw될 수 있습니다. 명시적 숫자 변환은 다음과 같이 처리됩니다.
- 정수 계열 형식에서 다른 정수 계열 형식으로 변환하는 경우 처리는 변환이 수행되는 오버플로 검사 컨텍스트(§12.8.20)에 따라 달라집니다.
-
checked
컨텍스트에서 원본 피연산자의 값이 대상 형식의 범위 내에 있지만 원본 피연산자의 값이 대상 형식 범위를 벗어나면 변환에 성공합니다System.OverflowException
. -
unchecked
컨텍스트에서 변환은 항상 성공하고 다음과 같이 진행됩니다.- 원본 형식이 대상 형식보다 큰 경우 가장 중요한 "추가" 비트를 삭제하여 원본 값이 잘립니다. 그런 다음, 결과는 대상 형식의 값으로 처리됩니다.
- 원본 형식이 대상 형식과 크기가 같으면 원본 값이 대상 형식의 값으로 처리됩니다.
-
- 정수 계열 형식으로
decimal
변환하는 경우 원본 값은 0에서 가장 가까운 정수 값으로 반올림되고 이 정수 값은 변환의 결과가 됩니다. 결과 정수 값이 대상 형식의 범위를 벗어나면 throwSystem.OverflowException
됩니다. - 정수 형식에서
float
정double
수 형식으로 변환하는 경우 처리는 변환이 수행되는 오버플로 검사 컨텍스트(§12.8.20)에 따라 달라집니다.- 확인된 컨텍스트에서 변환은 다음과 같이 진행됩니다.
- 피연산자의 값이 NaN이거나 무한이면 throw
System.OverflowException
됩니다. - 그렇지 않으면 소스 피연산자는 0으로 반올림되어 가장 가까운 정수 값으로 반올림됩니다. 이 정수 값이 대상 형식의 범위 내에 있는 경우 이 값은 변환의 결과입니다.
- 그렇지 않으면
System.OverflowException
이 throw됩니다.
- 피연산자의 값이 NaN이거나 무한이면 throw
- 확인되지 않은 컨텍스트에서 변환은 항상 성공하고 다음과 같이 진행됩니다.
- 피연산자의 값이 NaN이거나 무한이면 변환 결과는 대상 형식의 지정되지 않은 값입니다.
- 그렇지 않으면 소스 피연산자는 0으로 반올림되어 가장 가까운 정수 값으로 반올림됩니다. 이 정수 값이 대상 형식의 범위 내에 있는 경우 이 값은 변환의 결과입니다.
- 그렇지 않으면 변환 결과는 대상 형식의 지정되지 않은 값입니다.
- 확인된 컨텍스트에서 변환은 다음과 같이 진행됩니다.
- 변환
double
float
double
의 경우 값은 가장float
가까운 값으로 반올림됩니다. 값이double
너무 작아서 표시float
할 수 없는 경우 결과는 값과 같은 부호가 있는 0이 됩니다. 값의double
크기가 너무 커서 값으로float
나타낼 수 없는 경우 결과는 값과 같은 부호가 있는 무한대 상태가 됩니다. 값이double
NaN이면 결과도 NaN입니다. - 변환의
float
double
decimal
경우 원본 값이 표현으로decimal
변환되고 필요한 경우 가장 가까운 숫자(§8.3.8)로 반올림됩니다.- 원본 값이 너무 작아서 표시
decimal
할 수 없는 경우 결과가 0이 되어 부호 있는 0 값을 지원하는 경우decimal
원래 값의 부호를 유지합니다. - 원본 값의 크기가 너무 커서 표시할
decimal
수 없거나 해당 값이 무한대이면 소수 표현이 무한대를 지원하는 경우 원래 값의 부호를 유지합니다. 그렇지 않으면 System.OverflowException이 throw됩니다. - 원본 값이 NaN이면 10진수 표현이 NaN을 지원하는 경우 결과는 NaN입니다. 그렇지 않으면 System.OverflowException이 throw됩니다.
- 원본 값이 너무 작아서 표시
- 변환
decimal
float
double
decimal
의 경우 값이 가장double
가까운 값 또는float
값으로 반올림됩니다. 원본 값의 크기가 너무 커서 대상 형식을 나타내지 않거나 해당 값이 무한대이면 결과는 원래 값의 부호를 유지합니다. 원본 값이 NaN이면 결과는 NaN입니다. 이 변환은 정밀도를 잃을 수 있지만 예외가 throw되지는 않습니다.
참고: 형식은
decimal
무한대 또는 NaN 값을 지원할 필요는 없지만 그렇게 할 수 있습니다. 해당 범위는 범위float
double
및 범위보다 작을 수 있지만 보장되지는 않습니다. 무한대 또는 NaN 값이 없고 범위가 보다decimal
작은 표현의 경우float
무한대 또는decimal
NaN으로 변환float
double
한 결과가 발생합니다. 끝 메모
10.3.3 명시적 열거형 변환
명시적 열거형 변환은 다음과 같습니다.
- from
sbyte
,byte
, ,short
,ushort
int
,uint
,long
,ulong
,char
,float
,double
또는decimal
enum_type. - 모든 enum_type , ,
sbyte
,byte
,short
,ushort
int
,uint
,long
ulong
,char
float
또는double
.decimal
- 모든 enum_type 다른 enum_type.
두 형식 간의 명시적 열거형 변환은 참여하는 모든 enum_type 해당 enum_type 기본 형식으로 처리한 다음 결과 형식 간에 암시적 또는 명시적 숫자 변환을 수행하여 처리됩니다.
예: 기본 형식이 있는 enum_type
int
경우 변환E
byte
은 명시적 숫자 변환(§10.3.2)int
byte
으로 처리되고byte
E
변환은 암시적 숫자 변환(§10.2.3)byte
int
으로 처리됩니다. 끝 예제
10.3.4 명시적 nullable 변환
명시적 nullable 변환은 명시적 및 암시적 미리 정의된 변환에서 파생된 nullable 변환(§10.6.1)입니다.
10.3.5 명시적 참조 변환
명시적 참조 변환은 다음과 같습니다.
- 개체에서 다른 reference_type.
- class_type
T
class_type 기본 클래스S
인 경우 .T
- 모든 class_type
S
interface_type,T
봉인되지 않고 제공된S
경우S
구현T
되지 않습니다. - interface_type
T
class_type 봉인되지 않았거나 구현을T
제공했습니다.S
- 제공
T
S
interface_type 파생되지T
않습니다. - 요소 형식이 있는 array_type
S
요소 형식Sᵢ
이 있는 array_typeT
Tᵢ
다음이 모두 true인 경우-
S
요소T
형식에서만 다릅니다. 즉,S
T
동일한 수의 차원이 있습니다. - 명시적 참조 변환이 있습니다
Sᵢ
Tᵢ
.
-
-
System.Array
구현하는 인터페이스와 array_type. - ID 변환 또는 명시적 참조 변환이 있는 경우 1차원
System.Collections.Generic.IReadOnlyList<T>
및 해당 기본 인터페이스로S
T
변환합니다. -
System.Collections.Generic.IList<S>
ID 변환 또는 명시적 참조 변환이 있는 경우 해당 기본 인터페이스에서System.Collections.Generic.IReadOnlyList<S>
T[]
1차원 배열 형식S
으로 변환합니다. -
System.Delegate
구현하는 인터페이스와 delegate_type. - 참조 형식에서 참조 형식
S
T
으로의 명시적 참조 변환이 있고S
ID 변환이 있는 경우 참조 형식에서T₀
T₀
참조 형식T₀
으로 변환합니다T
. - 참조 형식에서 인터페이스 또는 대리자 형식
S
T
으로의 명시적 참조 변환S
이 있고T₀
분산 변환이 가능한T₀
경우 또는 분산 변환이 §18.2.3.3으로 변환 가능한 경우 인터페이스 또는T
대리자 형식T
으로 변환할 수 있습니다T₀
. -
D<S₁...Sᵥ>
제D<T₁...Tᵥ>
네릭 대리자 형식D<X₁...Xᵥ>
이 있는 위치D<S₁...Sᵥ>
까지 다음의 각 형식 매개 변수D<T₁...Tᵥ>
Xᵢ
에 대해 호환되거나 동일D
하지 않습니다.- 고정
Xᵢ
Sᵢ
된 경우Tᵢ
. - 공변성인 경우
Xᵢ
ID 변환, 암시적 참조 변환 또는 명시적 참조 변환이Sᵢ
Tᵢ
있습니다. - 반공변성
Xᵢ
Sᵢ
인 경우Tᵢ
동일하거나 둘 다 참조 형식입니다.
- 고정
- 참조 형식으로 알려진 형식 매개 변수와 관련된 명시적 변환입니다. 형식 매개 변수와 관련된 명시적 변환에 대한 자세한 내용은 §10.3.8을 참조하세요.
명시적 참조 변환은 올바른지 확인하기 위해 런타임 검사가 필요한 reference_type간의 변환입니다.
런타임에 명시적 참조 변환이 성공하려면 원본 피연산자의 값이 되거나 null
소스 피연산자가 참조하는 개체의 형식은 암시적 참조 변환(§10.2.8)을 통해 대상 형식으로 변환할 수 있는 형식이어야 합니다. 명시적 참조 변환이 실패하면 throw System.InvalidCastException
됩니다.
참고: 참조 변환(암시적 또는 명시적)은 참조 자체의 값(§8.2.1)을 변경하지 않고 해당 형식만 변경하지 않습니다. 참조되는 개체의 형식이나 값도 변경되지 않습니다. 끝 메모
10.3.6 명시적 튜플 변환
튜플 식 E
에서 튜플 형식 T
E
으로의 명시적 변환이 T
존재하며, 암시적 또는 명시적 변환이 각 요소에서 해당 요소 E
형식 T
으로 존재합니다. 변환은 해당 형식의 T
인스턴스를 만들고, 해당하는 튜플 요소 식을 System.ValueTuple<...>
평가하고, 찾은 명시적 변환을 사용하는 해당 요소 형식 E
으로 변환하고, 결과를 사용하여 필드를 초기화하여 각 필드를 왼쪽에서 오른쪽으로 순서대로 초기화하여 수행 T
됩니다.
10.3.7 Unboxing 변환
unboxing 변환을 사용하면 reference_type 명시적으로 value_type 변환할 수 있습니다. 다음과 같은 unboxing 변환이 있습니다.
- 형식
object
에서 모든 value_type. - 형식
System.ValueType
에서 모든 value_type. - 형식
System.Enum
에서 모든 enum_type. - interface_type interface_type 구현하는 모든 non_nullable_value_type.
- interface_type
I₀
이 있는 non_nullable_value_type interface_type. - interface_type
I
interface_type non_nullable_value_type 언박싱 변환I₀
이 있고I₀
분산 변환이 variance_convertibleI
I
(§18.2.3.3)로 변환할 수 있는I₀
non_nullable_value_type. - reference_type reference_type nullable_value_type 기본 non_nullable_value_type 언박싱 변환이 있는 nullable_value_type.
- 값 형식으로 알려져 있지 않은 형식 매개 변수에서 §10.3.8에서 변환이 허용되도록 모든 형식으로 변환합니다.
non_nullable_value_type 대한 unboxing 작업은 먼저 개체 인스턴스가 지정된 non_nullable_value_type boxed 값인지 확인한 다음 인스턴스에서 값을 복사하는 것으로 구성됩니다.
nullable_value_type 언박싱하면 원본 피연산자가 있는 경우 nullable_value_type null 값이 생성되고null
, 그렇지 않으면 개체 인스턴스를 nullable_value_type 기본 형식으로 언박싱한 래핑된 결과가 생성됩니다.
참고: §10.2.9에 설명된 가상 boxing 클래스를 참조하여 개체 상자를 value_type
S
언박싱 변환은 식을((S_Boxing)box).value
실행하는 것으로 구성됩니다. 따라서 문object box = new S(); S s = (S)box;
개념적으로
object box = new S_Boxing(new S()); S s = ((S_Boxing)box).value;
끝 메모
런타임에 성공하기 위해 지정된 non_nullable_value_type 대한 unboxing 변환의 경우 원본 피연산자의 값은 해당 non_nullable_value_type boxed 값에 대한 참조여야 합니다. 원본 피연산자인 null
경우 throw System.NullReferenceException
됩니다. 소스 피연산자가 호환되지 않는 개체에 대한 참조이면 throw System.InvalidCastException
됩니다.
런타임에 성공하기 위해 지정된 nullable_value_type 대한 unboxing 변환의 경우 원본 피연산자의 값은 null이거나 nullable_value_type 기본 non_nullable_value_typeboxed 값에 대한 참조여야 합니다. 소스 피연산자가 호환되지 않는 개체에 대한 참조이면 throw System.InvalidCastException
됩니다.
10.3.8 형식 매개 변수와 관련된 명시적 변환
참조 형식(§15.2.5)으로 알려진 type_parameter T
경우 다음과 같은 명시적 참조 변환(§10.3.5)이 있습니다.
- 에 대한 모든 기본 클래스
C
의T
T
유효 기본 클래스C
T
에서 . - 모든 interface_type .
T
-
T
I
암시적 참조 변환T
I
이 아직 없는 경우 interface_type. -
T
(§15.2.5T
U
따라 제공되는 항목입니다.참고:
T
참조 형식으로 알려져 있으므로 범위 내에서T
런타임 형식은 컴파일 타임에 참조 형식으로 알려져 있지 않더라도U
항상 참조 형식이 됩니다. 끝 메모
참조 형식(§15.2.5)으로 알려져 있지 않은T
경우 컴파일 타임에 다음과 같은 T
변환이 unboxing 변환(§10.3.7)으로 간주됩니다. 런타임에 값 형식인 경우 T
변환은 unboxing 변환으로 실행됩니다. 런타임에 참조 형식인 경우 T
변환은 명시적 참조 변환 또는 ID 변환으로 실행됩니다.
- 에 대한 모든 기본 클래스
C
의T
T
유효 기본 클래스C
T
에서 .참고: C는 형식 중 하나이거나
System.Object
참조System.ValueType
형식System.Enum
T
으로 알려져 있습니다. 끝 메모 - 모든 interface_type .
T
참조 형식(§15.2.5)으로 알려져 있지 않은T
경우 다음과 같은 명시적 변환이 존재합니다.
-
T
I
암시적 변환T
I
이 없는 경우 interface_type. 이 변환은 암시적 boxing 변환(§10.2.9I
런타임에 값 형식인 경우T
변환은 boxing 변환으로 실행된 다음 명시적 참조 변환으로 실행됩니다. 런타임에 참조 형식인 경우T
변환은 명시적 참조 변환으로 실행됩니다. - 형식 매개 변수에서 (
U
)에T
의존하는 제공T
된 매개 변수U
입니다. 런타임에 값 형식이고T
참조 형식인 경우U
변환은 unboxing 변환으로 실행됩니다. 런타임에 둘 다T
값 형식U
T
인U
경우 반드시 동일한 형식이며 변환이 수행되지 않습니다. 런타임에 참조 형식인 경우T
반드시 참조 형식U
이기도 하며 변환은 명시적 참조 변환 또는 ID 변환으로 실행됩니다.
모든 경우에 규칙은 런타임에 변환이 참조 형식에서 값 형식으로 변환되는 경우에만 변환이 unboxing 변환으로 실행되도록 합니다.
위의 규칙은 제약이 없는 형식 매개 변수에서 비 인터페이스 형식으로의 직접 명시적 변환을 허용하지 않습니다. 이는 놀라운 일이 될 수 있습니다. 이 규칙의 이유는 혼동을 방지하고 이러한 변환의 의미 체계를 명확하게 하기 위한 것입니다.
예: 다음 선언을 고려합니다.
class X<T> { public static long F(T t) { return (long)t; // Error } }
직접 명시적 변환
t
long
이 허용된 경우 반환X<int>.F(7)
될 것으로 쉽게 예상7L
할 수 있습니다. 그러나 표준 숫자 변환은 형식이 바인딩 타임에 숫자로 알려진 경우에만 고려되기 때문에 그렇지 않습니다. 의미 체계를 명확하게 하려면 위의 예제를 대신 작성해야 합니다.class X<T> { public static long F(T t) { return (long)(object)t; // Ok, but will only work when T is long } }
이제 이 코드는 컴파일되지만 boxed
X<int>.F(7)
를 직접 변환할 수 없으므로 실행int
하면 런타임에 예외가long
throw됩니다.끝 예제
10.3.9 사용자 정의 명시적 변환
사용자 정의 명시적 변환은 선택적 표준 명시적 변환과 사용자 정의 암시적 또는 명시적 변환 연산자를 실행한 다음 다른 선택적 표준 명시적 변환으로 구성됩니다. 사용자 정의 명시적 변환을 평가하기 위한 정확한 규칙은 §10.5.5에 설명되어 있습니다.
10.4 표준 변환
10.4.1 일반
표준 변환은 사용자 정의 변환의 일부로 발생할 수 있는 미리 정의된 변환입니다.
10.4.2 표준 암시적 변환
다음 암시적 변환은 표준 암시적 변환으로 분류됩니다.
- ID 변환(§10.2.2)
- 암시적 숫자 변환(§10.2.3)
- 암시적 nullable 변환(§10.2.6)
- Null 리터럴 변환(§10.2.7)
- 암시적 참조 변환(§10.2.8)
- Boxing 변환(§10.2.9)
- 암시적 상수 식 변환(§10.2.11)
- 형식 매개 변수와 관련된 암시적 변환(§10.2.12)
표준 암시적 변환은 특히 사용자 정의 암시적 변환을 제외합니다.
10.4.3 표준 명시적 변환
표준 명시적 변환은 모두 표준 암시적 변환과 반대되는 표준 암시적 변환이 존재하는 명시적 변환의 하위 집합입니다.
참고: 즉, 표준 암시적 변환이 형식에서 형식
A
B
으로 존재하는 경우 형식에서 형식으로,A
형식에서 형식B
으로B
표준 명시적 변환이A
존재합니다. 끝 메모
10.5 사용자 정의 변환
10.5.1 일반
C#을 사용하면 미리 정의된 암시적 및 명시적 변환을 사용자 정의 변환에 의해 보강할 수 있습니다. 사용자 정의 변환은 클래스 및 구조체 형식에서 변환 연산자(§15.10.4)를 선언하여 도입됩니다.
10.5.2 허용되는 사용자 정의 변환
C#에서는 특정 사용자 정의 변환만 선언할 수 있습니다. 특히 기존 암시적 또는 명시적 변환을 다시 정의할 수 없습니다.
지정된 원본 형식 및 대상 형식 S
T
의 경우 null 허용 값 형식인 S
경우 T
해당 기본 형식을 참조 S₀
T₀
하고, 그렇지 않으면 S₀
같 T₀
고 S
T
각각을 참조합니다. 클래스 또는 구조체는 다음이 모두 true인 경우에만 원본 형식에서 대상 형식 S
T
으로의 변환을 선언할 수 있습니다.
-
S₀
은T₀
서로 다른 형식입니다. -
S₀
T₀
또는 연산자 선언이 수행되는 클래스 또는 구조체 형식입니다. -
S₀
interface_type 것도 아닙니다T₀
. - 사용자 정의 변환을 제외하면 변환
S
T
T
S
이 있습니다.
사용자 정의 변환에 적용되는 제한 사항은 §15.10.4에 지정됩니다.
10.5.3 사용자 정의 변환 평가
사용자 정의 변환은 원본 형식이 있을 수 있는 원본 식을 대상 형식이라는 다른 형식으로 변환합니다. 사용자 정의 변환 평가는 원본 식 및 대상 형식에 대한 가장 구체적인 사용자 정의 변환 연산자를 찾는 데 중점을 두고 있습니다. 이 결정은 다음과 같은 여러 단계로 구분됩니다.
- 사용자 정의 변환 연산자를 고려할 클래스 및 구조체 집합을 찾습니다. 원본 형식이 있는 경우 이 집합은 원본 형식 및 해당 기본 클래스와 대상 형식 및 기본 클래스로 구성됩니다. 이를 위해 클래스와 구조체만 사용자 정의 연산자를 선언할 수 있고 클래스가 아닌 형식에는 기본 클래스가 없다고 가정합니다. 또한 원본 또는 대상 형식이 nullable-value-type인 경우 해당 기본 형식이 대신 사용됩니다.
- 해당 형식 집합에서 적용할 수 있는 사용자 정의 및 해제된 변환 연산자를 결정합니다. 변환 연산자를 적용하려면 원본 식에서 연산자의 피연산자 형식으로 표준 변환(§10.4)을 수행할 수 있으며, 연산자의 결과 형식에서 대상 형식으로 표준 변환을 수행할 수 있어야 합니다.
- 적용 가능한 사용자 정의 연산자 집합에서 가장 구체적인 연산자를 결정합니다. 일반적으로 가장 구체적인 연산자는 피연산자 형식이 원본 식에 "가장 가깝고" 결과 형식이 대상 형식에 "가장 가까운" 연산자입니다. 사용자 정의 변환 연산자는 해제된 변환 연산자보다 선호됩니다. 가장 구체적인 사용자 정의 변환 연산자를 설정하기 위한 정확한 규칙은 다음 하위 클래스에 정의되어 있습니다.
가장 구체적인 사용자 정의 변환 연산자가 식별되면 사용자 정의 변환의 실제 실행에는 최대 3단계가 포함됩니다.
- 먼저 필요한 경우 원본 식에서 사용자 정의 또는 해제된 변환 연산자의 피연산자 형식으로 표준 변환을 수행합니다.
- 다음으로, 변환을 수행하기 위해 사용자 정의 또는 해제된 변환 연산자를 호출합니다.
- 마지막으로 필요한 경우 사용자 정의 변환 연산자의 결과 형식에서 대상 형식으로 표준 변환을 수행합니다.
사용자 정의 변환 평가에는 둘 이상의 사용자 정의 변환 연산자 또는 해제된 변환 연산자가 포함되지 않습니다. 즉, 형식에서 형식 S
T
으로의 변환은 먼저 사용자 정의 변환을 실행한 후 사용자 정의 변환 S
X
X
을 실행하지 T
않습니다.
- 사용자 정의 암시적 또는 명시적 변환의 평가에 대한 정확한 정의는 다음 하위 클래스에 제공됩니다. 정의는 다음 용어를 사용합니다.
- 표준 암시적 변환(§10.4.2)이 형식에서 형식
A
으로 존재하고 interface_typeB
B
하고 포함B
이라고 합니다.A
- 표준 암시적 변환(§10.4.2)이 식
E
에서 형식B
으로 존재하고 형식이 없는 경우(있는 경우B
E
) interface_typeB
이라고 하며B
이를 포괄E
- 형식 집합에서 가장 포괄적인 형식은 집합의 다른 모든 형식을 포괄하는 형식입니다. 다른 모든 형식을 포함하는 단일 형식이 없으면 집합에 가장 포괄적인 형식이 없습니다. 보다 직관적인 용어로 가장 포괄하는 형식은 집합에서 "가장 큰" 형식으로, 다른 형식을 각각 암시적으로 변환할 수 있는 형식입니다.
- 형식 집합에서 가장 많이 포괄되는 형식은 집합의 다른 모든 형식으로 포괄되는 형식입니다. 다른 모든 형식으로 포괄되는 단일 형식이 없으면 집합에 가장 포괄적인 형식이 없습니다. 보다 직관적인 용어로 가장 포괄적인 형식은 집합에서 "가장 작은" 형식이며, 한 형식은 암시적으로 다른 각 형식으로 변환할 수 있습니다.
10.5.4 사용자 정의 암시적 변환
식에서 E
형식 T
으로의 사용자 정의 암시적 변환은 다음과 같이 처리됩니다.
형식
S
S₀
및T₀
.- 형식이 있는 경우
E
해당 형식으로 지정합니다S
. - nullable 값 형식이거나
S
nullable인T
Sᵢ
경우Tᵢ
기본 형식이 되도록 하고, 그렇지 않으면 각각 그대로Sᵢ
두거나Tᵢ
S
사용할 수T
있습니다. - 형식 매개 변수이거나
Sᵢ
형식 매개 변수인 경우Tᵢ
유효 기본 클래스가 되게S₀
T₀
하고, 그렇지 않으면 각각 허용S₀
하고T₀
Sₓ
사용할 수Tᵢ
있습니다.
- 형식이 있는 경우
사용자 정의 변환 연산자가 고려될 형식
D
집합을 찾습니다. 이 집합은 (존재하고 클래스 또는 구조체인 경우S₀
), 기본 클래스S₀
(존재하고 클래스인 경우S₀
), 클래스S₀
또는 구조체인 경우T₀
)로 구성T₀
됩니다. 집합D
에 이미 포함된 다른 형식으로의 ID 변환이 없는 경우에만 형식이 집합에 추가됩니다.적용 가능한 사용자 정의 및 해제된 변환 연산자
U
집합을 찾습니다. 이 집합은 해당 클래스 또는 구조체D
에서 선언한 사용자 정의 및 해제된 암시적 변환 연산자를 포괄하는 형식에서 포괄E
하는 형식으로 변환합니다T
. 비어 있으면U
변환이 정의되지 않고 컴파일 시간 오류가 발생합니다.- 있는 경우
S
및 변환U
에서 연산S
자 중 하나는 다음과Sₓ
같습니다S
. - 그렇지 않으면
Sₓ
연산U
자의 결합된 소스 형식 집합에서 가장 많이 포괄되는 형식입니다. 가장 포괄적인 형식을 정확히 하나 찾을 수 없는 경우 변환이 모호하고 컴파일 시간 오류가 발생합니다.
- 있는 경우
다음에서 연산자의 가장 구체적인 대상 형식
Tₓ
을 찾습니다.U
- 변환
U
T
할 연산Tₓ
자가 있으면 .입니다T
. - 그렇지 않으면
Tₓ
연산U
자의 대상 형식 집합에서 가장 포괄하는 형식입니다. 가장 포괄적인 형식을 정확히 하나 찾을 수 없는 경우 변환이 모호하고 컴파일 시간 오류가 발생합니다.
- 변환
가장 구체적인 변환 연산자를 찾습니다.
- 변환되는 사용자 정의 변환 연산자를
U
Sₓ
정확히 한 개 포함하는 경우Tₓ
가장 구체적인 변환 연산자입니다. - 그렇지 않은 경우 변환하는 리프트된 변환 연산자가
U
Sₓ
정확히 하나만 포함된 경우Tₓ
가장 구체적인 변환 연산자입니다. - 그렇지 않으면 변환이 모호하고 컴파일 시간 오류가 발생합니다.
- 변환되는 사용자 정의 변환 연산자를
마지막으로 변환을 적용합니다.
- E에 형식
Sₓ
이 아직 없으면 표준 암시적 변환E
Sₓ
이 수행됩니다. - 가장 구체적인 변환 연산자는 .로
Sₓ
Tₓ
변환하기 위해 호출됩니다. - 그렇지 않은
Tₓ
경우T
표준 암시적 변환이Tₓ
T
수행됩니다.
- E에 형식
형식 변수에서 형식 S
으로의 사용자 정의 암시적 변환이 있는 경우 형식에서 형식 T
S
T
으로의 사용자 정의 암시적 변환이 존재합니다.
10.5.5 사용자 정의 명시적 변환
식에서 E
형식 T
으로의 사용자 정의 명시적 변환은 다음과 같이 처리됩니다.
- 형식
S
S₀
및T₀
.- 형식이 있는 경우
E
해당 형식으로 지정합니다S
. - nullable 값 형식이거나
S
nullable인T
Sᵢ
경우Tᵢ
기본 형식이 되도록 하고, 그렇지 않으면 각각 그대로Sᵢ
두거나Tᵢ
S
사용할 수T
있습니다. - 형식 매개 변수이거나
Sᵢ
형식 매개 변수인 경우Tᵢ
유효 기본 클래스가 되게S₀
T₀
하고, 그렇지 않으면 각각 허용S₀
하고T₀
Sᵢ
사용할 수Tᵢ
있습니다.
- 형식이 있는 경우
- 사용자 정의 변환 연산자가 고려될 형식
D
집합을 찾습니다. 이 집합은 (존재하고 클래스 또는 구조체인 경우S₀
), 기본 클래스S₀
(존재하고 클래스인 경우S₀
), (클래스 또는 구조체인 경우S₀
)T₀
및 기본 클래스T₀
(클래스인 경우T₀
)로 구성T₀
됩니다.A
형식은 집합D
에 이미 포함된 다른 형식으로의 ID 변환이 없는 경우에만 집합에 추가됩니다. - 적용 가능한 사용자 정의 및 해제된 변환 연산자
U
집합을 찾습니다. 이 집합은 해당 클래스 또는 구조D
체가 선언한 사용자 정의 및 해제된 암시적 또는 명시적 변환 연산자를 포함하거나 포괄E
S
하는 형식(있는 경우)에서 포괄하거나 포괄하는 형식으로T
변환하는 것으로 구성됩니다. 비어 있으면U
변환이 정의되지 않고 컴파일 시간 오류가 발생합니다. - 다음에서 연산자의 가장 구체적인 원본 형식
Sₓ
을 찾습니다.U
- S가 있고 변환
U
S
할 연산Sₓ
자가 있으면 다음과 같습니다S
. - 그렇지 않은 경우 해당 연산자의 결합된 소스 형식 집합에서
U
가장 포괄되는 형식을 포함하는E
Sₓ
형식에서 변환하는 연산자 중 한 가지가 있습니다. 가장 포괄적인 형식을 찾을 수 없는 경우 변환이 모호하고 컴파일 시간 오류가 발생합니다. - 그렇지 않으면
Sₓ
연산U
자의 결합된 소스 형식 집합에서 가장 포괄하는 형식입니다. 가장 포괄적인 형식을 정확히 하나 찾을 수 없는 경우 변환이 모호하고 컴파일 시간 오류가 발생합니다.
- S가 있고 변환
- 다음에서 연산자의 가장 구체적인 대상 형식
Tₓ
을 찾습니다.U
- 변환
U
T
할 연산Tₓ
자가 있으면 .입니다T
. - 그렇지 않은 경우 변환되는 연산자 중 해당 연산자가 포괄하는 형식으로 변환되는
U
T
경우 해당 연Tₓ
산자의 결합된 대상 형식 집합에서 가장 포괄하는 형식입니다. 가장 포괄적인 형식을 정확히 하나 찾을 수 없는 경우 변환이 모호하고 컴파일 시간 오류가 발생합니다. - 그렇지 않으면
Tₓ
연산U
자의 결합된 대상 형식 집합에서 가장 많이 포괄되는 형식입니다. 가장 포괄적인 형식을 찾을 수 없는 경우 변환이 모호하고 컴파일 시간 오류가 발생합니다.
- 변환
- 가장 구체적인 변환 연산자를 찾습니다.
- U에서 변환하는 사용자 정의 변환 연산자가
Sₓ
Tₓ
정확히 한 개 있는 경우 가장 구체적인 변환 연산자입니다. - 그렇지 않은 경우 변환하는 리프트된 변환 연산자가
U
Sₓ
정확히 하나만 포함된 경우Tₓ
가장 구체적인 변환 연산자입니다. - 그렇지 않으면 변환이 모호하고 컴파일 시간 오류가 발생합니다.
- U에서 변환하는 사용자 정의 변환 연산자가
- 마지막으로 변환을 적용합니다.
- 형식
E
이 아직 없는 경우Sₓ
E에서 표준 명시적 변환이Sₓ
수행됩니다. - 가장 구체적인 사용자 정의 변환 연산자는 변환
Sₓ
Tₓ
을 위해 호출됩니다. - 그렇지 않은
Tₓ
경우T
표준 명시적 변환이Tₓ
T
수행됩니다.
- 형식
형식 변수에서 형식 S
으로의 사용자 정의 명시적 변환이 있는 경우 형식에서 형식 T
S
T
으로의 사용자 정의 명시적 변환이 존재합니다.
10.6 nullable 형식과 관련된 변환
10.6.1 Nullable 변환
Nullable 변환은 nullable이 아닌 값 형식에서 작동하는 미리 정의된 변환도 해당 형식의 nullable 형식과 함께 사용할 수 있도록 허용합니다. null을 허용하지 않는 값 형식에서 null을 허용하지 않는 S
값 형식T
(§10.2.2, §10.2.3, §10.2.4, §10.2.11, §10.3.2 및 §10.3.3)으로 변환하는 미리 정의된 각 암시적 또는 명시적 변환에 대해 다음 nullable 변환이 존재합니다.
- 암시적 또는 명시적 변환
S?
T?
- 암시적 또는 명시적 변환
S
T?
- 에서 .로
S?
의 명시적 변환T
입니다.
nullable 변환 자체는 암시적 또는 명시적 변환으로 분류됩니다.
특정 nullable 변환은 표준 변환으로 분류되며 사용자 정의 변환의 일부로 발생할 수 있습니다. 특히 모든 암시적 nullable 변환은 표준 암시적 변환(§10.4.2)으로 분류되며 § 10.4.3의 요구 사항을 충족하는 명시적 nullable 변환은 표준 명시적 변환으로 분류됩니다.
다음과 같이 진행에서 진행으로의 기본 변환을 기반으로 nullable 변환 S
T
을 평가합니다.
- nullable 변환이 다음으로
S?
T?
변환되는 경우:- 원본 값이 null(
HasValue
속성)false
이면 결과는 형식T?
의 null 값입니다. - 그렇지 않으면 변환이 래핑
S?
S
해제로 평가되고, 그 다음에는 기본 변환이S
T
이어서 줄 바꿈T
이T?
수행됩니다.
- 원본 값이 null(
- nullable 변환이 원본
S
T?
인 경우 변환은 기본 변환에서S
T
다음으로의 래핑T
T?
으로 평가됩니다. - nullable 변환이 원본
S?
T
인 경우 변환은 래핑 해제로S?
S
평가되고 그 다음에는 기본 변환이S
T
수행됩니다.
10.6.2 변환 해제됨
nullable이 아닌 값 형식에서 nullable이 아닌 값 S
형식 T
으로 변환하는 사용자 정의 변환 연산자가 있는 경우 해제된 변환 연산자가 S?
T?
있습니다. 이 해제된 변환 연산자는 null 값이 null 값으로 직접 변환된다는 점을 제외하고 래핑 S?
S
해제를 수행한 다음 사용자 정의 변환 S
T
에서 다음으로 T
T?
의 래핑을 수행합니다.S?
T?
리프트된 변환 연산자는 기본 사용자 정의 변환 연산자로 암시적 또는 명시적 분류가 동일합니다.
10.7 익명 함수 변환
10.7.1 일반
anonymous_method_expression 또는 lambda_expression 익명 함수(§12.19)로 분류됩니다. 식에는 형식이 없지만 호환되는 대리자 형식으로 암시적으로 변환할 수 있습니다. 일부 람다 식은 호환되는 식 트리 형식으로 암시적으로 변환될 수도 있습니다.
특히 익명 함수 F
는 제공된 대리자 형식 D
과 호환됩니다.
- anonymous_function_signature
F
D
경우F
동일한 수의 매개 변수를 갖습니다. - anonymous_function_signature
F
포함되어 있지 않으면D
출력 매개 변수가 없는 한 모든 형식의 매개 변수D
가 0개 이상 있을 수 있습니다. - 명시적으로 형식화된 매개 변수 목록이 있는
F
경우D
각 매개 변수는 해당 매개 변수와 동일한 한정자를 가지며 해당 매개 변수F
F
간에 ID 변환이 존재합니다. - 암시적으로 형식화된 매개 변수 목록이
F
있는 경우D
참조 또는 출력 매개 변수가 없습니다. - 본문이
F
식이고D
void 반환 형식이 있거나«TaskType»
(§15.15.1)이면 각 매개 변수의F
형식이 해당 매개 변수D
의 형식으로 지정되면 본문F
은 statement_expression(§13.7)로 허용되는 유효한 식(w.r.t §12)입니다. - 본문이
F
블록이고D
void 반환 형식F
비동기 형식이고D
«TaskType»
반환 형식이 있는 경우 각 매개 변수의F
형식이 해당 매개 변수D
의 형식으로 지정되면 해당 본문F
은 식을 지정하지 않는 유효한 블록(w.r.treturn
)입니다. - 본문
F
이 식이고F
비동기 형식이거나D
반환 형식F
비동기D
«TaskType»<T>
형식(§15.15.1)이면 각 매개 변수의F
형식이 해당 매개 변수D
의 형식으로 지정되면 본문F
은 암시적으로 변환할 수 있는 유효한 식(w.r.tT
)입니다. - 본문
F
이 블록이고F
비동기이고D
비효과 반환 형식T
F
비동기 형식이거나D
«TaskType»<T>
반환 형식이 있는 경우 각 매개 변수에F
해당하는 매개 변수D
F
의 형식이 지정되면 각 반환 문이 암시적으로 변환할 수 있는 식을 지정하는 유효한 문 블록(w.r.tT
)입니다.
예제: 다음 예제에서는 이러한 규칙을 보여 줍니다.
delegate void D(int x); D d1 = delegate { }; // Ok D d2 = delegate() { }; // Error, signature mismatch D d3 = delegate(long x) { }; // Error, signature mismatch D d4 = delegate(int x) { }; // Ok D d5 = delegate(int x) { return; }; // Ok D d6 = delegate(int x) { return x; }; // Error, return type mismatch delegate void E(out int x); E e1 = delegate { }; // Error, E has an output parameter E e2 = delegate(out int x) { x = 1; }; // Ok E e3 = delegate(ref int x) { x = 1; }; // Error, signature mismatch delegate int P(params int[] a); P p1 = delegate { }; // Error, end of block reachable P p2 = delegate { return; }; // Error, return type mismatch P p3 = delegate { return 1; }; // Ok P p4 = delegate { return "Hello"; }; // Error, return type mismatch P p5 = delegate(int[] a) // Ok { return a[0]; }; P p6 = delegate(params int[] a) // Error, params modifier { return a[0]; }; P p7 = delegate(int[] a) // Error, return type mismatch { if (a.Length > 0) return a[0]; return "Hello"; }; delegate object Q(params int[] a); Q q1 = delegate(int[] a) // Ok { if (a.Length > 0) return a[0]; return "Hello"; };
끝 예제
예제: 다음 예제에서는 형식
Func<A,R>
의 인수를 사용하고 형식의 값을 반환하는 함수를 나타내는 제네릭 대리자 형식A
R
을 사용합니다.delegate R Func<A,R>(A arg);
배정에서
Func<int,int> f1 = x => x + 1; // Ok Func<int,double> f2 = x => x + 1; // Ok Func<double,int> f3 = x => x + 1; // Error Func<int, Task<int>> f4 = async x => x + 1; // Ok
각 익명 함수의 매개 변수 및 반환 형식은 무명 함수가 할당된 변수의 형식에서 결정됩니다.
첫 번째 할당은 형식이 지정된 경우 형식으로 암시적으로 변환할 수 있는 유효한 식이므로 무명 함수를 대리
Func<int,int>
자 형식x
int
x + 1
으로 변환합니다.int
마찬가지로 두 번째 할당은 형식의 결과가 < 암시적으로 형식으로 변환될 수 >있기 때문에 무명 함수를 대리자 형식
x + 1
Funcint
int,doubledouble
로 변환합니다.그러나 세 번째 할당은 형식이 지정된 경우
x
형식의double
x + 1
결과가 암시적으로 형식double
으로 변환할 수int
없기 때문에 컴파일 시간 오류입니다.네 번째 할당은 (형식
Func<int, Task<int>>
의) 결과가 반환 형식x + 1
이 있는 비동기 람다의int
유효 반환 형식으로 암시적으로 변환할 수 있기 때문에 익명 비동기 함수를 대리자 형식int
Task<int>
으로 변환합니다.끝 예제
람다 식 F
은 대리자 형식 Expression<D>
과 호환되는 경우 F
식 트리 형식 D
과 호환됩니다. 익명 메서드에는 적용되지 않고 람다 식에만 적용됩니다.
익명 함수는 오버로드 확인에 영향을 줄 수 있으며 형식 유추에 참여할 수 있습니다. 자세한 내용은 §12.6을 참조하세요.
10.7.2 대리자 형식으로 익명 함수 변환 평가
익명 함수를 대리자 형식으로 변환하면 익명 함수를 참조하는 대리자 인스턴스와 평가 시 활성 상태인 캡처된 외부 변수 집합이 생성됩니다. 대리자를 호출하면 익명 함수의 본문이 실행됩니다. 본문의 코드는 대리자가 참조하는 캡처된 외부 변수 집합을 사용하여 실행됩니다. 익명 메서드를 대리자 형식으로 변환하기 위한 대체 구문으로 delegate_creation_expression(§12.8.17.6)를 사용할 수 있습니다.
익명 함수에서 생성된 대리자의 호출 목록에는 단일 항목이 포함됩니다. 대리자의 정확한 대상 개체 및 대상 메서드는 지정되지 않습니다. 특히 대리 null
this
자의 대상 개체가 바깥쪽 함수 멤버의 값인지 또는 다른 개체인지는 지정되지 않습니다.
동일한 대리자 형식으로 캡처된 외부 변수 인스턴스의 동일한(비어 있음) 집합을 사용하여 의미상 동일한 익명 함수를 동일한 대리자 인스턴스를 반환할 수 있습니다(필수는 아님). 여기서 의미 체계적으로 동일한 용어는 익명 함수의 실행이 모든 경우에 동일한 인수를 감안할 때 동일한 효과를 생성한다는 것을 의미하기 위해 사용됩니다. 이 규칙은 다음과 같은 코드를 최적화할 수 있도록 허용합니다.
delegate double Function(double x);
class Test
{
static double[] Apply(double[] a, Function f)
{
double[] result = new double[a.Length];
for (int i = 0; i < a.Length; i++)
{
result[i] = f(a[i]);
}
return result;
}
static void F(double[] a, double[] b)
{
a = Apply(a, (double x) => Math.Sin(x));
b = Apply(b, (double y) => Math.Sin(y));
...
}
}
두 익명 함수 대리자는 캡처된 외부 변수의 동일한(빈) 집합을 가지므로 익명 함수는 의미상 동일하므로 컴파일러는 대리자가 동일한 대상 메서드를 참조하도록 허용됩니다. 실제로 컴파일러는 두 익명 함수 식에서 동일한 대리자 인스턴스를 반환할 수 있습니다.
10.7.3 식 트리 형식으로의 람다 식 변환 평가
람다 식을 식 트리 형식으로 변환하면 식 트리(§8.6)가 생성됩니다. 보다 정확하게 말해, 람다 식 변환을 계산하면 람다 식 자체의 구조를 나타내는 개체 구조가 생성됩니다.
모든 람다 식을 식 트리 형식으로 변환할 수 있는 것은 아닙니다. 호환되는 대리자 형식으로의 변환은 항상 존재하지만 구현 정의 이유로 컴파일 타임에 실패할 수 있습니다.
참고: 람다 식이 식 트리 형식으로 변환되지 못하는 일반적인 이유는 다음과 같습니다.
- 블록 본문이 있습니다.
- 한정자가
async
있습니다.- 할당 연산자를 포함합니다.
- 출력 또는 참조 매개 변수를 포함합니다.
- 동적으로 바인딩된 식을 포함합니다.
끝 메모
10.8 메서드 그룹 변환
메서드 그룹(§12.2)에서 호환되는 대리자 형식(§20.4)으로 암시적 변환이 존재합니다. 대리자 형식이고 D
메서드 그룹으로 E
D
분류되는 식인 경우 E
다음 설명에 설명된 대로 형식과 한정자가 E
일치하는 인수 목록(§12.6.6.2)에 일반 형식(§12.6.4.2)에 적용할 수 있는 메서드가 하나 이상 포함되어 있는 경우에만 D
호환됩니다.
메서드 그룹에서 E
대리자 형식 D
으로 변환하는 컴파일 시간 애플리케이션은 다음에 설명되어 있습니다.
- 다음과 같이 양식
M
의 메서드 호출(§12.8.10.2)에 해당하는 단일 메서드E(A)
가 선택됩니다.- 인수 목록은
A
각각 변수로 분류되고 parameter_list 해당 매개 변수의 형식 및 한정자(in
out
또는ref
)로 분류되는 식 목록D
이며, 형식dynamic
의 매개 변수를 제외하고 해당 식에는 형식 대신object
형식dynamic
이 있습니다. - 고려되는 후보 메서드는 정상적인 형식으로 적용할 수 있는 메서드일 뿐이며 선택적 매개 변수(§12.6.4.2)를 생략하지 않습니다. 따라서 후보 메서드는 확장된 형식에서만 적용할 수 있거나 하나 이상의 선택적 매개 변수에 해당 매개 변수가 없는 경우 무시됩니다
D
.
- 인수 목록은
- §12.8.10.2 알고리즘이 호환되는 단일 최상의 방법(
M
)D
을 생성하는 경우 변환이 존재하는 것으로 간주됩니다. - 선택한 메서드가 인스턴스 메서드
M
인 경우 연결된E
인스턴스 식에 따라 대리자의 대상 개체가 결정됩니다. - 선택한 메서드
M
가 인스턴스 식에 대한 멤버 액세스를 통해 표시되는 확장 메서드인 경우 해당 인스턴스 식은 대리자의 대상 개체를 결정합니다. - 변환 결과는 형식
D
의 값, 즉 선택한 메서드 및 대상 개체를 참조하는 대리자입니다.
예제: 다음은 메서드 그룹 변환을 보여 줍니다.
delegate string D1(object o); delegate object D2(string s); delegate object D3(); delegate string D4(object o, params object[] a); delegate string D5(int i); class Test { static string F(object o) {...} static void G() { D1 d1 = F; // Ok D2 d2 = F; // Ok D3 d3 = F; // Error – not applicable D4 d4 = F; // Error – not applicable in normal form D5 d5 = F; // Error – applicable but not compatible } }
메서드 그룹을
d1
형식F
의 값으로 암시적으로 변환하는 할당D1
입니다.파생(반공변성) 매개 변수 형식이 적고 파생된(공변성) 반환 형식이 더 많은 메서드에 대리자를 만드는 방법을 보여 주는 할당
d2
입니다.메서드를 적용할
d3
수 없는 경우 변환이 존재하지 않는 방법을 보여 주려는 할당입니다.메서드를
d4
일반 형식으로 적용할 수 있는 방법을 보여 주려는 할당입니다.대리자와 메서드의 매개 변수 및 반환 형식이 참조 형식에 대해서만 다를 수 있는 방법을 보여 주려는 할당
d5
입니다.끝 예제
다른 모든 암시적 및 명시적 변환과 마찬가지로 캐스트 연산자를 사용하여 특정 변환을 명시적으로 수행할 수 있습니다.
예: 따라서 예제
object obj = new EventHandler(myDialog.OkClick);
대신 쓸 수 있습니다.
object obj = (EventHandler)myDialog.OkClick;
끝 예제
메서드 그룹 변환은 형식 인수를 E
명시적으로 지정하거나 형식 유추(§12.6.3)를 통해 제네릭 메서드를 참조할 수 있습니다. 형식 유추를 사용하는 경우 대리자의 매개 변수 형식은 유추 프로세스에서 인수 형식으로 사용됩니다. 대리자의 반환 형식은 유추에 사용되지 않습니다. 형식 인수가 지정되거나 유추되는지 여부에 관계없이 메서드 그룹 변환 프로세스의 일부입니다. 결과 대리자를 호출할 때 대상 메서드를 호출하는 데 사용되는 형식 인수입니다.
예제:
delegate int D(string s, int i); delegate int E(); class X { public static T F<T>(string s, T t) {...} public static T G<T>() {...} static void Main() { D d1 = F<int>; // Ok, type argument given explicitly D d2 = F; // Ok, int inferred as type argument E e1 = G<int>; // Ok, type argument given explicitly E e2 = G; // Error, cannot infer from return type } }
끝 예제
메서드 그룹은 오버로드 확인에 영향을 줄 수 있으며 형식 유추에 참여할 수 있습니다. 자세한 내용은 §12.6을 참조하세요.
메서드 그룹 변환의 런타임 평가는 다음과 같이 진행됩니다.
- 컴파일 시간에 선택한 메서드가 인스턴스 메서드이거나 인스턴스 메서드로 액세스되는 확장 메서드인 경우 대리자의 대상 개체는 다음과 연결된
E
인스턴스 식에서 결정됩니다.- 인스턴스 식이 평가됩니다. 이 평가에서 예외가 발생하면 추가 단계가 실행되지 않습니다.
- 인스턴스 식이 reference_type 경우 인스턴스 식에서 계산한 값이 대상 개체가 됩니다. 선택한 메서드가 인스턴스 메서드이고 대상 개체인
null
경우 throwSystem.NullReferenceException
되고 더 이상 단계가 실행되지 않습니다. - 인스턴스 식이 value_type 경우 값을 개체로 변환하기 위해 boxing 연산(§10.2.9)이 수행되고 이 개체는 대상 개체가 됩니다.
- 그렇지 않으면 선택한 메서드는 정적 메서드 호출의 일부이며 대리자의 대상 개체는 .입니다
null
. - 대리자 형식
D
의 대리자 인스턴스는 컴파일 시간에 결정된 메서드에 대한 참조와 다음과 같이 위에서 계산된 대상 개체에 대한 참조를 사용하여 가져옵니다.- 변환은 이러한 참조가 이미 포함된 기존 대리자 인스턴스를 사용할 수 있도록 허용됩니다(필수는 아님).
- 기존 인스턴스를 다시 사용하지 않으면 새 인스턴스가 만들어집니다(§20.5). 새 인스턴스를 할당하는 데 사용할 수 있는 메모리가 충분하지 않으면 throw
System.OutOfMemoryException
됩니다. 그렇지 않으면 인스턴스가 지정된 참조를 사용하여 초기화됩니다.
ECMA C# draft specification