2011-10-20 3 views
4

다음 코드는 Main 함수의 두 번째 줄에있는 제목의 오류를 제공합니다.운영자 '??' 하위 클래스의 피연산자에 적용 할 수 없습니다.

public class P {} 

public class B : P {} 

public class A : P {} 

void Main() 
{ 
    P p = GetA()??GetB(); 
} 

public A GetA() 
{ 
    return new A(); 
} 

public B GetB() 
{ 
    return new B(); 
} 

p = (P)GetA()??GetB(); 
    or 
    p = GetA()??(P)GetB(); 

작품 같은 라인에 간단한 비틀기.

저는 왜 컴파일러가 양쪽 모두 왼쪽 컨테이너의 하위 클래스이며 캐스트없이 작업 할 수 있는지 이해하지 못하는지 궁금합니다.

답변

6

왼쪽의 인수 유형은 오른쪽의 형식과 호환되어야하며 그 반대도 마찬가지입니다. 즉, B에서 A 또는 A에서 B으로의 암시 적 변환이 있어야합니다. yx 내지 암시 적 변환이 존재하는 경우 상기에서

var a = x ?? y; 

x의 타입 식의 형태가된다. y에서 x으로의 암시 적 변환은 없지만 x에서 y으로의 암시 적 변환이있는 경우 y 유형이 표현식의 유형이됩니다. 어느 방향으로도 변환이 없다면 붐; 컴파일 오류. 사양에서 :

식의 유형은 ?? b는 피연산자 유형간에 사용 가능한 암시 적 변환에 따라 다릅니다. 선호도 순서대로, ?? b는 A0, A 또는 B입니다. 여기서 A는 a의 유형이고, B는 b의 유형이고 (b는 유형이있는 경우) A가 A가 널 (NULL) 입력 가능 유형이면 A의 기본 유형입니다. . 특히, ?? b는 다음과 같이 처리됩니다.

• A가 null 입력 가능 유형 또는 참조 유형이 아니면 컴파일 타임 오류가 발생합니다.

• A가 Null 허용 유형이고 b에서 A0으로의 암시 적 변환이있는 경우 결과 유형은 A0입니다. 런타임에 a가 먼저 평가됩니다. a가 null가 아닌 경우, a는 A0를 타이핑하기 위해서 랩핑 해제됩니다. 이것은 결과가됩니다. 그렇지 않으면 b가 평가되어 A0 유형으로 변환되고 이것이 결과가됩니다.

• 그렇지 않으면 암시 적 변환이 b에서 A로 진행되는 경우 결과 유형은 A입니다. 런타임에 a가 먼저 평가됩니다. a가 null가 아닌 경우, a가 결과가됩니다. 그렇지 않으면 b가 평가되어 유형 A로 변환되고 이것이 결과가됩니다.

• 그렇지 않으면 b의 유형이 B이고 암시 적 변환이 A0에서 B까지 존재하는 경우 결과 유형은 B입니다. 런타임에는 a가 먼저 평가됩니다. a가 null이 아닌 경우, a는 A0 (A와 A0가 같은 형태가 아닌 한)를 랩핑 해, B 형으로 변환 해, 결과가됩니다. 그렇지 않으면 b가 계산되어 결과가됩니다.

? 그렇지 않으면 a와 b가 호환되지 않으며 컴파일 타임 오류가 발생합니다.

+0

아 내가보고, 내가 할 때 예를 다시 읽고 LHS의 종류는 것을 깨달았다 매우 복잡 코멘트를 작성하는 과정에 있었다 RHS에 표현의 평가에서 파생 된. 처음에는'x'와'y'가 모두'a'로 변환 될 수 있으면 좋겠다고 생각했습니다. – Joe

+0

예, 할당되는 변수의 유형을 포함하여 가장 직선적 인 방법이며 정확하게 처음에는 어떻게 작동하는지 생각했을 것입니다. 이런 식으로 설계된 이유에 관해서는 Eric Lippert와 같은 사람의 이야기를 듣고 싶습니다. –

-1

연산자의 피연산자 ??동일한 유형이어야합니다 :

P a = GetA(); 
    P b = GetB(); 
    P p = a ?? b; 
+1

그들은 같은 유형일 필요는 없으며 단순히 암시적인 변환이 존재해야합니다. –

1

컴파일러가 모두 왼쪽 컨테이너의 하위 클래스임을 이해하고 캐스트없이 조작을 허가하지 않는 이유가 궁금 하군요?

는 다음이 허용 될 것입니다 때문에 :

public class SqlConnection : object {}  
public class Random : object {} 

public SqlConnection GetA() { return new SqlConnection(); } 
public Random GetB() { return new Random(); } 

void Main() 
{ 
    var p = GetA() ?? GetB(); 
} 
+0

+1 예를 들어 좋아해요 :) –

+0

윙윙 거리다. 'var p = (object) GetA() ?? GetB();'가 허용됩니다. 그것은 구문 적으로 다를 수 있지만 동일한 논리적 목적을 달성합니다. – Joe

+0

@Joe : 당신은 무엇이든 객체에 캐스트 할 수 있습니다. B에서 객체로의 암시 적 변환이 있기 때문에 결과 표현식이 object를 반환합니다. 여기에서 var를 사용하면 캐스트를 수행 할 때 p가 type 객체가되므로 예제가 아플 수 있습니다. –

관련 문제