다음을 통해 공유


10 변환

10.1 일반

변환으로 인해 식이 특정 형식으로 변환되거나 특정 형식으로 처리됩니다. 이전의 경우 변환에는 표현 변경이 포함될 수 있습니다. 변환은 암시적 또는 명시적수 있으며 명시적 캐스트가 필요한지 여부를 결정합니다.

: 예를 들어 형식에서 형식 intlong 으로의 변환은 암시적이므로 형식 int 의 식은 암시적으로 형식 long으로 처리될 수 있습니다. 형식에서 형식 longint으로의 반대 변환은 명시적이므로 명시적 캐스트가 필요합니다.

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 일반

다음 변환은 암시적 변환으로 분류됩니다.

함수 멤버 호출(§12.6.6), 캐스트 식(§12.9.7) 및 할당(§12.21)을 비롯한 다양한 상황에서 암시적 변환이 발생할 수 있습니다.

미리 정의된 암시적 변환은 항상 성공하며 예외가 throw되지 않습니다.

참고: 올바르게 디자인된 사용자 정의 암시적 변환도 이러한 특성을 나타내야 합니다. 끝 메모

변환을 위해 형식 objectdynamic ID 변환 가능(§10.2.2)입니다.

그러나 동적 변환(§10.2.10)은 형식 dynamic 의 식(§8.2.4)에만 적용됩니다.

10.2.2 ID 변환

ID 변환은 모든 형식에서 동일한 형식 또는 런타임 시 동일한 형식으로 변환됩니다. 이 변환이 존재하는 이유 중 하나는 형식 또는 형식 TT 의 식을 자체로 변환 T 할 수 있기 때문입니다. 다음과 같은 ID 변환이 존재합니다.

  • 사이 TT모든 형식 T에 대해 .
  • 참조 형식 간 TT? 모든 참조 형식 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;

튜플 t1t2 의 형식과 t3 모두 두 개의 요소가 int 있습니다. 그 뒤에는 .가 string있습니다. 튜플 요소 형식은 튜플에서와 같이 t4, t5t6. 중첩된 튜플을 포함하여 해당 요소 형식의 각 쌍 간에 ID 변환이 존재하므로 튜플 형식과 t4튜플 형식 간에 ID 변환이 존재합니다.t5t6

끝 예제

모든 ID 변환은 대칭입니다. ID 변환이 있는 T₁T₂경우 ID 변환이 존재합니다 T₂T₁. 두 형식 사이에 ID 변환이 있는 경우 두 형식은 ID 변환이 가능 합니다.

대부분의 경우 ID 변환은 런타임에 영향을 주지 않습니다. 그러나 부동 소수점 연산은 해당 형식(§8.3.7)에 의해 규정된 것보다 높은 정밀도로 수행될 수 있으므로 결과를 할당하면 정밀도가 손실될 수 있으며 명시적 캐스트는 형식(§12.9.7)에 의해 규정된 정밀도를 줄이도록 보장됩니다.

10.2.3 암시적 숫자 변환

암시적 숫자 변환은 다음과 같습니다.

  • From tosbyteshort, int, long, float, double또는 decimal.
  • From to byteshort, ushort, , int, uintlong, ulong, float, double또는 decimal.
  • From to shortint, long, float, double또는 decimal.
  • From toushortint, uint, , longulong, float, double또는 decimal.
  • From to intlong, float, double또는 decimal.
  • From to uintlong, ulong, float, double또는 decimal.
  • From to longfloat, double또는 decimal.
  • From to ulongfloat, double또는 decimal.
  • From to charushort, int, , uintlong, ulong, float, double또는 decimal.
  • float ~ double입니다.

또는 그 안 intuintlongulongfloatlong을 오가 ulongdouble 변환으로 인해 정밀도가 손실될 수 있지만 크기가 손실되지는 않습니다. 다른 암시적 숫자 변환 시에는 정보 손실이 없습니다.

형식에 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 및 .objectdynamic
  • 모든 class_typeSclass_type .TST
  • 모든 ST interface_type 제공된 S 구현으로.T
  • 모든 TST interface_type .
  • 요소 형식이 있는 array_typeS 요소 형식 Sᵢ있는 array_typeTTᵢ다음이 모두 true인 경우
    • S 요소 T 형식에서만 다릅니다. 즉, ST 동일한 수의 차원이 있습니다.
    • 암시적 참조 변환이 있습니다 SᵢTᵢ.
  • 암시적 ID 또는 참조 변환이 있는 경우 1차원 배열 형식 S[]System.Collections.Generic.IList<T>System.Collections.Generic.IReadOnlyList<T>에서 S , 및 해당 기본 인터페이스로 변환합니다.T
  • 구현하는 인터페이스System.Array.
  • 구현하는 모든 delegate_typeSystem.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();
    }
}

이제 형식 vS 의 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);
    }
}

는 할당 pbox 에서 발생하는 암시적 boxing 작업으로 인해 값이 복사되기 때문에 콘솔에서 p 값 10을 출력합니다. 대신 선언되었 Point 으면 class 동일한 인스턴스를 참조하기 때문에 pbox 값 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

할당과 s2i 둘 다 암시적 동적 변환을 사용합니다. 여기서 작업의 바인딩은 런타임까지 일시 중단됩니다. 런타임 시 암시적 변환은 (d)의 string런타임 형식에서 대상 형식으로 검색됩니다. 변환은 다음으로 string 찾을 수 있지만 그렇지 않습니다 int.

끝 예제

10.2.11 암시적 상수 식 변환

암시적 상수 식 변환은 다음과 같은 변환을 허용합니다.

  • constant_expression 값이 대상 형식의 범위 내에 있는 경우 형식 의 constant_expressionulong
  • constant_expression 값이 음수가 아니면 형식 longulong 형식으로 변환할 수 있습니다.

10.2.12 형식 매개 변수와 관련된 암시적 변환

참조 형식(§15.2.5)으로 알려진 type_parameter T 경우 다음과 같은 암시적 참조 변환(§10.2.8)이 있습니다.

  • T 유효 기본 클래스부터 C 기본 클래스TC까지, 그리고 T 에서 구현된 C모든 인터페이스로.
  • 유효 인터페이스 집합 T 의 interface_type ITI
  • 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 기본 클래스TC까지, 그리고 T 에서 구현된 C모든 인터페이스로.

    참고: C 형식 중 하나이거나 System.Object 참조 System.ValueType 형식System.EnumT이라고도 합니다. 끝 메모

  • 유효 인터페이스 집합 T 의 interface_type ITI

참조 형식으로 T 경우 제공된 T 형식 매개 변수 UT 의 암시적 변환이 따라 달라집니다U. 런타임에 값 형식이고 T 참조 형식인 경우 U 변환은 boxing 변환으로 실행됩니다. 런타임에 둘 다 T 값 형식 UTU 경우 반드시 동일한 형식이며 변환이 수행되지 않습니다. 런타임에 참조 형식인 경우 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 형식 ETE 으로 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암시적 변환이 존재하기 때문에 , t2t4t5 및 의 선언은 모두 유효합니다. 로의 t3 변환 nullint이 없으므로 선언이 잘못되었습니다. 튜플 식의 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 sbytebyte, ushort, uint, ulong또는 char.
  • byte 으로 sbyte 또는 char.
  • From toshortsbyte, byte, ushort, uint, ulong또는 char.
  • From to ushortsbyte, byte, short또는 char.
  • From tointsbyte, byte, , shortushort, uint, ulong또는 char.
  • From touintsbyte, byte, short, ushort, int또는 char.
  • From to longsbyte, byte, , shortushort, int, uint, ulong또는 char.
  • From to ulongsbyte, byte, , shortushort, int, uint, long또는 char.
  • From to charsbyte, byte또는 short.
  • From to floatsbyte, byte, , short, ushortint, uint, long, ulong, char또는 decimal.
  • From to doublesbyte, byte, , short, ushortint, uint, long, ulong, char, float또는 decimal.
  • From to decimalsbyte, byte, , short, ushortint, uint, long, ulong, char, float또는 double.

명시적 변환에는 모든 암시적 및 명시적 숫자 변환이 포함되므로 캐스트 식(§12.9.7)을 사용하여 모든 numeric_type 다른 numeric_type 변환할 수 있습니다.

명시적 숫자 변환으로 인해 정보가 손실되거나 예외가 throw될 수 있습니다. 명시적 숫자 변환은 다음과 같이 처리됩니다.

  • 정수 계열 형식에서 다른 정수 계열 형식으로 변환하는 경우 처리는 변환이 수행되는 오버플로 검사 컨텍스트(§12.8.20)에 따라 달라집니다.
    • checked 컨텍스트에서 원본 피연산자의 값이 대상 형식의 범위 내에 있지만 원본 피연산자의 값이 대상 형식 범위를 벗어나면 변환에 성공합니다System.OverflowException.
    • unchecked 컨텍스트에서 변환은 항상 성공하고 다음과 같이 진행됩니다.
      • 원본 형식이 대상 형식보다 큰 경우 가장 중요한 "추가" 비트를 삭제하여 원본 값이 잘립니다. 그런 다음, 결과는 대상 형식의 값으로 처리됩니다.
      • 원본 형식이 대상 형식과 크기가 같으면 원본 값이 대상 형식의 값으로 처리됩니다.
  • 정수 계열 형식으로 decimal 변환하는 경우 원본 값은 0에서 가장 가까운 정수 값으로 반올림되고 이 정수 값은 변환의 결과가 됩니다. 결과 정수 값이 대상 형식의 범위를 벗어나면 throw System.OverflowException 됩니다.
  • 정수 형식에서 floatdouble 수 형식으로 변환하는 경우 처리는 변환이 수행되는 오버플로 검사 컨텍스트(§12.8.20)에 따라 달라집니다.
    • 확인된 컨텍스트에서 변환은 다음과 같이 진행됩니다.
      • 피연산자의 값이 NaN이거나 무한이면 throw System.OverflowException 됩니다.
      • 그렇지 않으면 소스 피연산자는 0으로 반올림되어 가장 가까운 정수 값으로 반올림됩니다. 이 정수 값이 대상 형식의 범위 내에 있는 경우 이 값은 변환의 결과입니다.
      • 그렇지 않으면 System.OverflowException이 throw됩니다.
    • 확인되지 않은 컨텍스트에서 변환은 항상 성공하고 다음과 같이 진행됩니다.
      • 피연산자의 값이 NaN이거나 무한이면 변환 결과는 대상 형식의 지정되지 않은 값입니다.
      • 그렇지 않으면 소스 피연산자는 0으로 반올림되어 가장 가까운 정수 값으로 반올림됩니다. 이 정수 값이 대상 형식의 범위 내에 있는 경우 이 값은 변환의 결과입니다.
      • 그렇지 않으면 변환 결과는 대상 형식의 지정되지 않은 값입니다.
  • 변환 doublefloatdouble 의 경우 값은 가장 float 가까운 값으로 반올림됩니다. 값이 double 너무 작아서 표시 float할 수 없는 경우 결과는 값과 같은 부호가 있는 0이 됩니다. 값의 double 크기가 너무 커서 값으로 float나타낼 수 없는 경우 결과는 값과 같은 부호가 있는 무한대 상태가 됩니다. 값이 double NaN이면 결과도 NaN입니다.
  • 변환의 floatdoubledecimal경우 원본 값이 표현으로 decimal 변환되고 필요한 경우 가장 가까운 숫자(§8.3.8)로 반올림됩니다.
    • 원본 값이 너무 작아서 표시 decimal할 수 없는 경우 결과가 0이 되어 부호 있는 0 값을 지원하는 경우 decimal 원래 값의 부호를 유지합니다.
    • 원본 값의 크기가 너무 커서 표시할 decimal수 없거나 해당 값이 무한대이면 소수 표현이 무한대를 지원하는 경우 원래 값의 부호를 유지합니다. 그렇지 않으면 System.OverflowException이 throw됩니다.
    • 원본 값이 NaN이면 10진수 표현이 NaN을 지원하는 경우 결과는 NaN입니다. 그렇지 않으면 System.OverflowException이 throw됩니다.
  • 변환 decimalfloatdoubledecimal의 경우 값이 가장 double 가까운 값 또는 float 값으로 반올림됩니다. 원본 값의 크기가 너무 커서 대상 형식을 나타내지 않거나 해당 값이 무한대이면 결과는 원래 값의 부호를 유지합니다. 원본 값이 NaN이면 결과는 NaN입니다. 이 변환은 정밀도를 잃을 수 있지만 예외가 throw되지는 않습니다.

참고: 형식은 decimal 무한대 또는 NaN 값을 지원할 필요는 없지만 그렇게 할 수 있습니다. 해당 범위는 범위 floatdouble및 범위보다 작을 수 있지만 보장되지는 않습니다. 무한대 또는 NaN 값이 없고 범위가 보다 decimal작은 표현의 경우 float 무한대 또는 decimal NaN으로 변환 floatdouble 한 결과가 발생합니다. 끝 메모

10.3.3 명시적 열거형 변환

명시적 열거형 변환은 다음과 같습니다.

  • fromsbyte, byte, , short, ushortint, uint, long, ulong, char, float, double또는 decimal enum_type.
  • 모든 enum_type , ,sbyte, byte,short, ushortint, uint, longulong, charfloat또는 double.decimal
  • 모든 enum_type 다른 enum_type.

두 형식 간의 명시적 열거형 변환은 참여하는 모든 enum_type 해당 enum_type 기본 형식으로 처리한 다음 결과 형식 간에 암시적 또는 명시적 숫자 변환을 수행하여 처리됩니다.

: 기본 형식이 있는 enum_typeint경우 변환 Ebyte 은 명시적 숫자 변환(§10.3.2)intbyte으로 처리되고 byteE 변환은 암시적 숫자 변환(§10.2.3)byteint으로 처리됩니다. 끝 예제

10.3.4 명시적 nullable 변환

명시적 nullable 변환은 명시적 및 암시적 미리 정의된 변환에서 파생된 nullable 변환(§10.6.1)입니다.

10.3.5 명시적 참조 변환

명시적 참조 변환은 다음과 같습니다.

  • 개체에서 다른 reference_type.
  • class_type T class_type 기본 클래스S인 경우 .T
  • 모든 class_typeS interface_type,T봉인되지 않고 제공된 S 경우 S 구현T되지 않습니다.
  • interface_type T class_type 봉인되지 않았거나 구현을 T제공했습니다.S
  • 제공TSinterface_type 파생되지 T않습니다.
  • 요소 형식이 있는 array_typeS 요소 형식 Sᵢ있는 array_typeTTᵢ다음이 모두 true인 경우
    • S 요소 T 형식에서만 다릅니다. 즉, ST 동일한 수의 차원이 있습니다.
    • 명시적 참조 변환이 있습니다 SᵢTᵢ.
  • System.Array 구현하는 인터페이스와 array_type.
  • ID 변환 또는 명시적 참조 변환이 있는 경우 1차원 System.Collections.Generic.IReadOnlyList<T> 및 해당 기본 인터페이스로 ST변환합니다.
  • System.Collections.Generic.IList<S>ID 변환 또는 명시적 참조 변환이 있는 경우 해당 기본 인터페이스에서 System.Collections.Generic.IReadOnlyList<S>T[] 1차원 배열 형식S으로 변환합니다.
  • System.Delegate 구현하는 인터페이스와 delegate_type.
  • 참조 형식에서 참조 형식 ST 으로의 명시적 참조 변환이 있고 S ID 변환이 있는 경우 참조 형식에서 T₀T₀ 참조 형식 T₀ 으로 변환합니다T.
  • 참조 형식에서 인터페이스 또는 대리자 형식 ST 으로의 명시적 참조 변환 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 에서 튜플 형식 TE 으로의 명시적 변환이 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 Iinterface_type non_nullable_value_type 언박싱 변환 I₀ 이 있고 I₀ 분산 변환이 variance_convertible II(§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_typeS 언박싱 변환은 식을 ((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)이 있습니다.

  • 에 대한 모든 기본 클래스 CTT 유효 기본 클래스 CT에서 .
  • 모든 interface_type .T
  • T I 암시적 참조 변환 TI이 아직 없는 경우 interface_type.
  • T (§15.2.5TU 따라 제공되는 항목입니다.

    참고: T 참조 형식으로 알려져 있으므로 범위 내에서 T런타임 형식은 컴파일 타임에 참조 형식으로 알려져 있지 않더라도 U 항상 참조 형식이 됩니다. 끝 메모

참조 형식(§15.2.5)으로 알려져 있지 않은T경우 컴파일 타임에 다음과 같은 T 변환이 unboxing 변환(§10.3.7)으로 간주됩니다. 런타임에 값 형식인 경우 T 변환은 unboxing 변환으로 실행됩니다. 런타임에 참조 형식인 경우 T 변환은 명시적 참조 변환 또는 ID 변환으로 실행됩니다.

  • 에 대한 모든 기본 클래스 CTT 유효 기본 클래스 CT에서 .

    참고: C는 형식 중 하나이거나 System.Object 참조 System.ValueType 형식System.EnumT으로 알려져 있습니다. 끝 메모

  • 모든 interface_type .T

참조 형식(§15.2.5)으로 알려져 있지 않은T경우 다음과 같은 명시적 변환이 존재합니다.

  • T I 암시적 변환 TI이 없는 경우 interface_type. 이 변환은 암시적 boxing 변환(§10.2.9I 런타임에 값 형식인 경우 T 변환은 boxing 변환으로 실행된 다음 명시적 참조 변환으로 실행됩니다. 런타임에 참조 형식인 경우 T 변환은 명시적 참조 변환으로 실행됩니다.
  • 형식 매개 변수에서 (U)에 T 의존하는 제공 T 된 매개 변수 U 입니다. 런타임에 값 형식이고 T 참조 형식인 경우 U 변환은 unboxing 변환으로 실행됩니다. 런타임에 둘 다 T 값 형식 UTU 경우 반드시 동일한 형식이며 변환이 수행되지 않습니다. 런타임에 참조 형식인 경우 T 반드시 참조 형식 U 이기도 하며 변환은 명시적 참조 변환 또는 ID 변환으로 실행됩니다.

모든 경우에 규칙은 런타임에 변환이 참조 형식에서 값 형식으로 변환되는 경우에만 변환이 unboxing 변환으로 실행되도록 합니다.

위의 규칙은 제약이 없는 형식 매개 변수에서 비 인터페이스 형식으로의 직접 명시적 변환을 허용하지 않습니다. 이는 놀라운 일이 될 수 있습니다. 이 규칙의 이유는 혼동을 방지하고 이러한 변환의 의미 체계를 명확하게 하기 위한 것입니다.

: 다음 선언을 고려합니다.

class X<T>
{
    public static long F(T t)
    {
        return (long)t;         // Error
    }
}

직접 명시적 변환 tlong 이 허용된 경우 반환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 하면 런타임에 예외가 longthrow됩니다.

끝 예제

10.3.9 사용자 정의 명시적 변환

사용자 정의 명시적 변환은 선택적 표준 명시적 변환과 사용자 정의 암시적 또는 명시적 변환 연산자를 실행한 다음 다른 선택적 표준 명시적 변환으로 구성됩니다. 사용자 정의 명시적 변환을 평가하기 위한 정확한 규칙은 §10.5.5설명되어 있습니다.

10.4 표준 변환

10.4.1 일반

표준 변환은 사용자 정의 변환의 일부로 발생할 수 있는 미리 정의된 변환입니다.

10.4.2 표준 암시적 변환

다음 암시적 변환은 표준 암시적 변환으로 분류됩니다.

표준 암시적 변환은 특히 사용자 정의 암시적 변환을 제외합니다.

10.4.3 표준 명시적 변환

표준 명시적 변환은 모두 표준 암시적 변환과 반대되는 표준 암시적 변환이 존재하는 명시적 변환의 하위 집합입니다.

참고: 즉, 표준 암시적 변환이 형식에서 형식 AB 으로 존재하는 경우 형식에서 형식으로, A 형식에서 형식 B 으로 B 표준 명시적 변환이 A존재합니다. 끝 메모

10.5 사용자 정의 변환

10.5.1 일반

C#을 사용하면 미리 정의된 암시적 및 명시적 변환을 사용자 정의 변환에 의해 보강할 수 있습니다. 사용자 정의 변환은 클래스 및 구조체 형식에서 변환 연산자(§15.10.4)를 선언하여 도입됩니다.

10.5.2 허용되는 사용자 정의 변환

C#에서는 특정 사용자 정의 변환만 선언할 수 있습니다. 특히 기존 암시적 또는 명시적 변환을 다시 정의할 수 없습니다.

지정된 원본 형식 및 대상 형식 ST의 경우 null 허용 값 형식인 S 경우 T 해당 기본 형식을 참조 S₀T₀ 하고, 그렇지 않으면 S₀T₀ST 각각을 참조합니다. 클래스 또는 구조체는 다음이 모두 true인 경우에만 원본 형식에서 대상 형식 ST 으로의 변환을 선언할 수 있습니다.

  • S₀T₀ 서로 다른 형식입니다.
  • S₀ T₀ 또는 연산자 선언이 수행되는 클래스 또는 구조체 형식입니다.
  • S₀ interface_type 것도 아닙니다 T₀.
  • 사용자 정의 변환을 제외하면 변환 STTS이 있습니다.

사용자 정의 변환에 적용되는 제한 사항은 §15.10.4지정됩니다.

10.5.3 사용자 정의 변환 평가

사용자 정의 변환은 원본 형식이 있을 수 있는 원본 식을 대상 형식이라는 다른 형식으로 변환합니다. 사용자 정의 변환 평가는 원본 식 및 대상 형식에 대한 가장 구체적인 사용자 정의 변환 연산자를 찾는 데 중점을 두고 있습니다. 이 결정은 다음과 같은 여러 단계로 구분됩니다.

  • 사용자 정의 변환 연산자를 고려할 클래스 및 구조체 집합을 찾습니다. 원본 형식이 있는 경우 이 집합은 원본 형식 및 해당 기본 클래스와 대상 형식 및 기본 클래스로 구성됩니다. 이를 위해 클래스와 구조체만 사용자 정의 연산자를 선언할 수 있고 클래스가 아닌 형식에는 기본 클래스가 없다고 가정합니다. 또한 원본 또는 대상 형식이 nullable-value-type인 경우 해당 기본 형식이 대신 사용됩니다.
  • 해당 형식 집합에서 적용할 수 있는 사용자 정의 및 해제된 변환 연산자를 결정합니다. 변환 연산자를 적용하려면 원본 식에서 연산자의 피연산자 형식으로 표준 변환(§10.4)을 수행할 수 있으며, 연산자의 결과 형식에서 대상 형식으로 표준 변환을 수행할 수 있어야 합니다.
  • 적용 가능한 사용자 정의 연산자 집합에서 가장 구체적인 연산자를 결정합니다. 일반적으로 가장 구체적인 연산자는 피연산자 형식이 원본 식에 "가장 가깝고" 결과 형식이 대상 형식에 "가장 가까운" 연산자입니다. 사용자 정의 변환 연산자는 해제된 변환 연산자보다 선호됩니다. 가장 구체적인 사용자 정의 변환 연산자를 설정하기 위한 정확한 규칙은 다음 하위 클래스에 정의되어 있습니다.

가장 구체적인 사용자 정의 변환 연산자가 식별되면 사용자 정의 변환의 실제 실행에는 최대 3단계가 포함됩니다.

  • 먼저 필요한 경우 원본 식에서 사용자 정의 또는 해제된 변환 연산자의 피연산자 형식으로 표준 변환을 수행합니다.
  • 다음으로, 변환을 수행하기 위해 사용자 정의 또는 해제된 변환 연산자를 호출합니다.
  • 마지막으로 필요한 경우 사용자 정의 변환 연산자의 결과 형식에서 대상 형식으로 표준 변환을 수행합니다.

사용자 정의 변환 평가에는 둘 이상의 사용자 정의 변환 연산자 또는 해제된 변환 연산자가 포함되지 않습니다. 즉, 형식에서 형식 ST 으로의 변환은 먼저 사용자 정의 변환을 실행한 후 사용자 정의 변환 SXX 을 실행하지 T않습니다.

  • 사용자 정의 암시적 또는 명시적 변환의 평가에 대한 정확한 정의는 다음 하위 클래스에 제공됩니다. 정의는 다음 용어를 사용합니다.
  • 표준 암시적 변환(§10.4.2)이 형식에서 형식 A으로 존재하고 interface_type BB하고 포함 B 이라고 합니다.A
  • 표준 암시적 변환(§10.4.2)이 식 E 에서 형식B으로 존재하고 형식이 없는 경우(있는 경우 BE) interface_typeB이라고 하며 B 이를 포괄E
  • 형식 집합에서 가장 포괄적인 형식은 집합의 다른 모든 형식을 포괄하는 형식입니다. 다른 모든 형식을 포함하는 단일 형식이 없으면 집합에 가장 포괄적인 형식이 없습니다. 보다 직관적인 용어로 가장 포괄하는 형식은 집합에서 "가장 큰" 형식으로, 다른 형식을 각각 암시적으로 변환할 수 있는 형식입니다.
  • 형식 집합에서 가장 많이 포괄되는 형식은 집합의 다른 모든 형식으로 포괄되는 형식입니다. 다른 모든 형식으로 포괄되는 단일 형식이 없으면 집합에 가장 포괄적인 형식이 없습니다. 보다 직관적인 용어로 가장 포괄적인 형식은 집합에서 "가장 작은" 형식이며, 한 형식은 암시적으로 다른 각 형식으로 변환할 수 있습니다.

10.5.4 사용자 정의 암시적 변환

식에서 E 형식 T 으로의 사용자 정의 암시적 변환은 다음과 같이 처리됩니다.

  • 형식 SS₀T₀.

    • 형식이 있는 경우 E 해당 형식으로 지정합니다 S .
    • nullable 값 형식이거나 S nullable인 TSᵢ 경우 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

    • 변환 UT 할 연산 Tₓ 자가 있으면 .입니다T.
    • 그렇지 않으면 Tₓ 연산 U자의 대상 형식 집합에서 가장 포괄하는 형식입니다. 가장 포괄적인 형식을 정확히 하나 찾을 수 없는 경우 변환이 모호하고 컴파일 시간 오류가 발생합니다.
  • 가장 구체적인 변환 연산자를 찾습니다.

    • 변환되는 사용자 정의 변환 연산자를 USₓ정확히 한 개 포함하는 경우 Tₓ 가장 구체적인 변환 연산자입니다.
    • 그렇지 않은 경우 변환하는 리프트된 변환 연산자가 USₓ정확히 하나만 포함된 경우 Tₓ 가장 구체적인 변환 연산자입니다.
    • 그렇지 않으면 변환이 모호하고 컴파일 시간 오류가 발생합니다.
  • 마지막으로 변환을 적용합니다.

    • E에 형식 Sₓ이 아직 없으면 표준 암시적 변환 ESₓ 이 수행됩니다.
    • 가장 구체적인 변환 연산자는 .로 SₓTₓ변환하기 위해 호출됩니다.
    • 그렇지 않은 Tₓ경우 T 표준 암시적 변환이 TₓT 수행됩니다.

형식 변수에서 형식 S 으로의 사용자 정의 암시적 변환이 있는 경우 형식에서 형식 TST으로의 사용자 정의 암시적 변환이 존재합니다.

10.5.5 사용자 정의 명시적 변환

식에서 E 형식 T 으로의 사용자 정의 명시적 변환은 다음과 같이 처리됩니다.

  • 형식 SS₀T₀.
    • 형식이 있는 경우 E 해당 형식으로 지정합니다 S .
    • nullable 값 형식이거나 S nullable인 TSᵢ 경우 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 체가 선언한 사용자 정의 및 해제된 암시적 또는 명시적 변환 연산자를 포함하거나 포괄 ES 하는 형식(있는 경우)에서 포괄하거나 포괄하는 형식으로 T변환하는 것으로 구성됩니다. 비어 있으면 U 변환이 정의되지 않고 컴파일 시간 오류가 발생합니다.
  • 다음에서 연산자의 가장 구체적인 원본 형식Sₓ을 찾습니다.U
    • S가 있고 변환 US 할 연산 Sₓ 자가 있으면 다음과 같습니다S.
    • 그렇지 않은 경우 해당 연산자의 결합된 소스 형식 집합에서 U 가장 포괄되는 형식을 포함하는 ESₓ 형식에서 변환하는 연산자 중 한 가지가 있습니다. 가장 포괄적인 형식을 찾을 수 없는 경우 변환이 모호하고 컴파일 시간 오류가 발생합니다.
    • 그렇지 않으면 Sₓ 연산 U자의 결합된 소스 형식 집합에서 가장 포괄하는 형식입니다. 가장 포괄적인 형식을 정확히 하나 찾을 수 없는 경우 변환이 모호하고 컴파일 시간 오류가 발생합니다.
  • 다음에서 연산자의 가장 구체적인 대상 형식Tₓ을 찾습니다.U
    • 변환 UT 할 연산 Tₓ 자가 있으면 .입니다T.
    • 그렇지 않은 경우 변환되는 연산자 중 해당 연산자가 포괄하는 형식으로 변환되는 UT 경우 해당 연 Tₓ 산자의 결합된 대상 형식 집합에서 가장 포괄하는 형식입니다. 가장 포괄적인 형식을 정확히 하나 찾을 수 없는 경우 변환이 모호하고 컴파일 시간 오류가 발생합니다.
    • 그렇지 않으면 Tₓ 연산 U자의 결합된 대상 형식 집합에서 가장 많이 포괄되는 형식입니다. 가장 포괄적인 형식을 찾을 수 없는 경우 변환이 모호하고 컴파일 시간 오류가 발생합니다.
  • 가장 구체적인 변환 연산자를 찾습니다.
    • U에서 변환하는 사용자 정의 변환 연산자가 SₓTₓ정확히 한 개 있는 경우 가장 구체적인 변환 연산자입니다.
    • 그렇지 않은 경우 변환하는 리프트된 변환 연산자가 USₓ정확히 하나만 포함된 경우 Tₓ 가장 구체적인 변환 연산자입니다.
    • 그렇지 않으면 변환이 모호하고 컴파일 시간 오류가 발생합니다.
  • 마지막으로 변환을 적용합니다.
    • 형식E이 아직 없는 경우 Sₓ E에서 표준 명시적 변환이 Sₓ 수행됩니다.
    • 가장 구체적인 사용자 정의 변환 연산자는 변환 SₓTₓ을 위해 호출됩니다.
    • 그렇지 않은 Tₓ경우 T 표준 명시적 변환이 TₓT 수행됩니다.

형식 변수에서 형식 S 으로의 사용자 정의 명시적 변환이 있는 경우 형식에서 형식 TST으로의 사용자 정의 명시적 변환이 존재합니다.

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?
  • 암시적 또는 명시적 변환 ST?
  • 에서 .로S?의 명시적 변환 T 입니다.

nullable 변환 자체는 암시적 또는 명시적 변환으로 분류됩니다.

특정 nullable 변환은 표준 변환으로 분류되며 사용자 정의 변환의 일부로 발생할 수 있습니다. 특히 모든 암시적 nullable 변환은 표준 암시적 변환(§10.4.2)으로 분류되며 § 10.4.3요구 사항을 충족하는 명시적 nullable 변환은 표준 명시적 변환으로 분류됩니다.

다음과 같이 진행에서 진행으로의 기본 변환을 기반으로 nullable 변환 ST 을 평가합니다.

  • nullable 변환이 다음으로 S?T?변환되는 경우:
    • 원본 값이 null(HasValue 속성) false이면 결과는 형식 T?의 null 값입니다.
    • 그렇지 않으면 변환이 래핑 S?S해제로 평가되고, 그 다음에는 기본 변환이 ST 이어서 줄 바꿈 TT?수행됩니다.
  • nullable 변환이 원본 ST?인 경우 변환은 기본 변환에서 ST 다음으로의 래핑 TT?으로 평가됩니다.
  • nullable 변환이 원본 S?T인 경우 변환은 래핑 해제로 S?S 평가되고 그 다음에는 기본 변환이 ST수행됩니다.

10.6.2 변환 해제됨

nullable이 아닌 값 형식에서 nullable이 아닌 값 S형식 T 으로 변환하는 사용자 정의 변환 연산자가 있는 경우 해제된 변환 연산자가 S?T?있습니다. 이 해제된 변환 연산자는 null 값이 null 값으로 직접 변환된다는 점을 제외하고 래핑 S?S 해제를 수행한 다음 사용자 정의 변환 ST 에서 다음으로 TT? 의 래핑을 수행합니다.S?T? 리프트된 변환 연산자는 기본 사용자 정의 변환 연산자로 암시적 또는 명시적 분류가 동일합니다.

10.7 익명 함수 변환

10.7.1 일반

anonymous_method_expression 또는 lambda_expression 익명 함수(§12.19)로 분류됩니다. 식에는 형식이 없지만 호환되는 대리자 형식으로 암시적으로 변환할 수 있습니다. 일부 람다 식은 호환되는 식 트리 형식으로 암시적으로 변환될 수도 있습니다.

특히 익명 함수 F 는 제공된 대리자 형식 D 과 호환됩니다.

  • anonymous_function_signature FD경우 F 동일한 수의 매개 변수를 갖습니다.
  • anonymous_function_signature F포함되어 있지 않으면 D 출력 매개 변수가 없는 한 모든 형식의 매개 변수 D 가 0개 이상 있을 수 있습니다.
  • 명시적으로 형식화된 매개 변수 목록이 있는 F 경우 D 각 매개 변수는 해당 매개 변수와 동일한 한정자를 가지며 해당 매개 변수 FF간에 ID 변환이 존재합니다.
  • 암시적으로 형식화된 매개 변수 목록이 F 있는 경우 D 참조 또는 출력 매개 변수가 없습니다.
  • 본문이 F 식이고Dvoid 반환 형식이 있거나«TaskType»(§15.15.1)이면 각 매개 변수의 F 형식이 해당 매개 변수D의 형식으로 지정되면 본문 F 은 statement_expression(§13.7)로 허용되는 유효한 식(w.r.t §12)입니다.
  • 본문이 F 블록이고 Dvoid 반환 형식F 비동기 형식이고 D«TaskType» 반환 형식이 있는 경우 각 매개 변수의 F 형식이 해당 매개 변수D의 형식으로 지정되면 해당 본문 F 은 식을 지정하지 않는 유효한 블록(w.r.t return)입니다.
  • 본문 F 이 식이고F비동기 형식이거나 D 반환 형식F 비동기 D«TaskType»<T> 형식(§15.15.1)이면 각 매개 변수의 F 형식이 해당 매개 변수D의 형식으로 지정되면 본문 F 은 암시적으로 변환할 수 있는 유효한 식(w.r.t T)입니다.
  • 본문 F 이 블록이고F 비동기이고 D 비효과 반환 형식TF 비동기 형식이거나 D«TaskType»<T> 반환 형식이 있는 경우 각 매개 변수에 F 해당하는 매개 변수 DF 의 형식이 지정되면 각 반환 문이 암시적으로 변환할 수 있는 식을 지정하는 유효한 문 블록(w.r.t T)입니다.

예제: 다음 예제에서는 이러한 규칙을 보여 줍니다.

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> 의 인수를 사용하고 형식의 값을 반환하는 함수를 나타내는 제네릭 대리자 형식 AR을 사용합니다.

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> 자 형식 xintx + 1으로 변환합니다.int

마찬가지로 두 번째 할당은 형식의 결과가 < 암시적으로 형식으로 변환될 수 >있기 때문에 무명 함수를 대리자 형식 x + 1Funcintint,doubledouble로 변환합니다.

그러나 세 번째 할당은 형식이 지정된 경우 x 형식의 doublex + 1 결과가 암시적으로 형식double으로 변환할 수 int없기 때문에 컴파일 시간 오류입니다.

네 번째 할당은 (형식Func<int, Task<int>>의) 결과가 반환 형식 x + 1 이 있는 비동기 람다의 int 유효 반환 형식으로 암시적으로 변환할 수 있기 때문에 익명 비동기 함수를 대리자 형식 intTask<int>으로 변환합니다.

끝 예제

람다 식 F 은 대리자 형식 Expression<D> 과 호환되는 경우 F 식 트리 형식 D과 호환됩니다. 익명 메서드에는 적용되지 않고 람다 식에만 적용됩니다.

익명 함수는 오버로드 확인에 영향을 줄 수 있으며 형식 유추에 참여할 수 있습니다. 자세한 내용은 §12.6을 참조하세요.

10.7.2 대리자 형식으로 익명 함수 변환 평가

익명 함수를 대리자 형식으로 변환하면 익명 함수를 참조하는 대리자 인스턴스와 평가 시 활성 상태인 캡처된 외부 변수 집합이 생성됩니다. 대리자를 호출하면 익명 함수의 본문이 실행됩니다. 본문의 코드는 대리자가 참조하는 캡처된 외부 변수 집합을 사용하여 실행됩니다. 익명 메서드를 대리자 형식으로 변환하기 위한 대체 구문으로 delegate_creation_expression(§12.8.17.6)를 사용할 수 있습니다.

익명 함수에서 생성된 대리자의 호출 목록에는 단일 항목이 포함됩니다. 대리자의 정확한 대상 개체 및 대상 메서드는 지정되지 않습니다. 특히 대리 nullthis 자의 대상 개체가 바깥쪽 함수 멤버의 값인지 또는 다른 개체인지는 지정되지 않습니다.

동일한 대리자 형식으로 캡처된 외부 변수 인스턴스의 동일한(비어 있음) 집합을 사용하여 의미상 동일한 익명 함수를 동일한 대리자 인스턴스를 반환할 수 있습니다(필수는 아님). 여기서 의미 체계적으로 동일한 용어는 익명 함수의 실행이 모든 경우에 동일한 인수를 감안할 때 동일한 효과를 생성한다는 것을 의미하기 위해 사용됩니다. 이 규칙은 다음과 같은 코드를 최적화할 수 있도록 허용합니다.

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 메서드 그룹으로 ED 분류되는 식인 경우 E 다음 설명에 설명된 대로 형식과 한정자가 E일치하는 인수 목록(§12.6.6.2)에 일반 형식(§12.6.4.2)에 적용할 수 있는 메서드가 하나 이상 포함되어 있는 경우에만 D 호환됩니다.

메서드 그룹에서 E 대리자 형식 D 으로 변환하는 컴파일 시간 애플리케이션은 다음에 설명되어 있습니다.

  • 다음과 같이 양식M의 메서드 호출(§12.8.10.2)에 해당하는 단일 메서드 E(A) 가 선택됩니다.
    • 인수 목록은 A 각각 변수로 분류되고 parameter_list 해당 매개 변수의 형식 및 한정자(inout또는 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경우 throw System.NullReferenceException 되고 더 이상 단계가 실행되지 않습니다.
    • 인스턴스 식이 value_type 경우 값을 개체로 변환하기 위해 boxing 연산(§10.2.9)이 수행되고 이 개체는 대상 개체가 됩니다.
  • 그렇지 않으면 선택한 메서드는 정적 메서드 호출의 일부이며 대리자의 대상 개체는 .입니다 null.
  • 대리자 형식 D 의 대리자 인스턴스는 컴파일 시간에 결정된 메서드에 대한 참조와 다음과 같이 위에서 계산된 대상 개체에 대한 참조를 사용하여 가져옵니다.
    • 변환은 이러한 참조가 이미 포함된 기존 대리자 인스턴스를 사용할 수 있도록 허용됩니다(필수는 아님).
    • 기존 인스턴스를 다시 사용하지 않으면 새 인스턴스가 만들어집니다(§20.5). 새 인스턴스를 할당하는 데 사용할 수 있는 메모리가 충분하지 않으면 throw System.OutOfMemoryException 됩니다. 그렇지 않으면 인스턴스가 지정된 참조를 사용하여 초기화됩니다.