2009-10-23 5 views
5

원하는 C# 다형성으로 왜 컴팩트화할 수 없습니까?

여기에 내가하고 싶은 일이있다.

XmlWriter writer = XmlWriter.Create(
    (string.IsNullOrEmpty(outfile) ? Console.Out : outfile) 
); 

그러나 컴파일 할 때 'System.IO.TextWriter'와 'string'사이에 암시적인 변환이 없기 때문에 "조건식의 유형을 결정할 수 없다. ''. 위의 코드는 다음을 단순화 한 것입니다.

XmlWriter writer; 

if (string.IsNullOrEmpty(outfile)) 
{ 
    writer = XmlWriter.Create(Console.Out); // Constructor takes TextWriter 
} 
else 
{ 
    writer = XmlWriter.Create(outfile); // Constructor takes string 
} 

이 두 Create 호출은 완벽하게 유효하며 컴파일됩니다. 인라인 테스트를 할 때처럼 컴팩트하게 만드는 방법이 있습니까?

내가 원하는 것은 효과가 없다는 것은 나에게 의미가 없습니다. 정신적으로 이것을 생각해 보면 컴파일러가 어떤 케이스를 결정할 지 string.IsNullOrEmpty(outfile)를 평가하는 것처럼 보입니다 :

  • 조건이 참이라면 Console.Out과 함께 가고 다형성으로 버전을 선택해야합니다. TextWriter를 사용하는 XmlWriter.Create
  • 조건이 false 인 경우 outfile과 함께 실행 한 다음 문자열을 사용하는 XmlWriter.Create의 버전을 다형성으로 선택해야합니다.

ML로 프로그래밍하면 내 뇌가 휘어 졌습니까?

답변

18

컴파일러는 컴파일 타임에 사용할 Create의 오버로드를 선택해야하기 때문에 런타임에 수행해야합니다. 당신이 그것을 할 수있는 최단는 아마도 :

XmlWriter writer = String.IsNullOrEmpty(outfile) 
    ? XmlWriter.Create(Console.Out) 
    : XmlWriter.Create(outfile); 
2

문제는 당신이

(string.IsNullOrEmpty(outfile) ? Console.Out : outfile) 

반환해야하는지 컴파일시에 확인할 수 있다는 것입니다. 문자열이 될 것인가 아니면 TextWriter가 될 것입니까? 런타임에만 결정될 수 있으므로 컴파일 오류가 발생합니다. 연산자는 컴파일 타임에 해결되어야합니다.

당신이 그것에서 얻을 수있는 최선은 아마도 다음과 같습니다 그들은 두 개의 별도의 생성자만큼

XmlWriter writer = string.IsNullOrEmpty(outfile) 
    ? XmlWriter.Create(Console.Out) 
    : XmlWriter.Create(outfile); 
1

아니, 당신은 두 개의 개별 통화를 할 수 있습니다.

호출 할 오버로드는 컴파일 타임에 결정되므로 런타임에 다른 오버로드를 호출하기 위해 데이터 유형을 선택할 수 없습니다.

또한 조건부 연산자는 단일 데이터 형식 만 반환 할 수 있으므로 choise에 따라 다른 데이터 형식을 반환 할 수 없습니다.

3

C# 컴파일러는 컴파일하는 동안 정적으로 실행할 메서드를 선택합니다. 컴파일 할 때 생성되는 IL은 특정 메소드에 대한 참조입니다. 다형성 부분은 실행할 특정 기능의 구현을 선택할 때 런타임에 제공됩니다.

? : : 문은 런타임에 평가되므로 컴파일러는 실행할 메서드를 알 수 없습니다.

변경하여 제대로 작동합니다.

XmlWriter writer = string.IsNullOrEmpty(outfile) ? 
    XmlWriter.Create(Console.Out) : 
    XmlWriter.Create(outfile); 
1

C#이 정적으로 입력되면 모든 다형성 마법이 컴파일 시간에 발생합니다. 그리고 컴파일 타임에 조건식의 유형을 알 수 없습니다.

+1

컴파일러는 컴파일시 클래스/메소드 이름과 인수를 선택하지만 런타임에 callvirt IL 명령어를 통해 해당 메소드의 구현을 다형 적으로 선택합니다. –

2

여기 몇 가지 일이 일어나고 있습니다.

먼저 "Ternary Operator (tm)"때문에 "예외"가 발생합니다. 사용하는 위치 때문에가 아닙니다. 문제는 하나의 공통 기본 유형 (객체 제외)으로 해결할 수없는 두 가지 유형을 반환하려고하는 단일 표현식을 가지고 있기 때문입니다.

또한 생성자 오버로드에는 어떤 방식으로도 관련이없는 완전히 다른 두 가지 유형이 사용됩니다. C# 컴파일러는 매우 매우 스마트하지만, 그것은 똑똑하지 않습니다.

7

모두가 다음과 같은 제안 것 같다 :

XmlWriter writer = String.IsNullOrEmpty(outfile) 
    ? XmlWriter.Create(Console.Out) 
    : XmlWriter.Create(outfile); 

그러나, 이것은 또한 행할 :

XmlWriter writer = XmlWriter.Create(string.IsNullOrEmpty(outfile) 
    ? Console.Out : new StreamWriter(outfile)); 

후자는 IMO, 컴팩트, 원래의 시도에 더 가깝다합니다.

관련 문제