2009-12-01 2 views
4

우리 프로그램이 프로덕션 서버에서 중단되었지만 개발 컴퓨터에서는 결코 중단되지 않는 문제를 디버깅하기 시작했습니다. 내 컴퓨터,이 코드 인쇄 "2"에서 실행하면같은 코드가 다른 컴퓨터에서 다르게 작동합니다. 원인은 무엇일까요? (CLR 버전 문제?)

using System; 
using System.Collections.Generic; 
using System.Linq; 

namespace RunTimeBug 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var coll = new Collection {{"Test", new Data()}, {"Test2", new Data()}}; 

      var dataSequence = coll.Cast<Data>().ToList(); 
      Console.WriteLine(dataSequence.Count); 
     } 
    } 

    class Collection : Dictionary<string,Data>, IEnumerable<Data> 
    { 
     public new IEnumerator<Data> GetEnumerator() 
     { 
      foreach(var v in Values) 
       yield return v; 
     } 
    } 

    class Data { } 
} 

:

내가 가진 문제를 재현 할 수이 작은 프로그램을 만들었습니다.

Unhandled Exception: System.InvalidCastException: Unable to cast object of type 'System.Collections.Generic.KeyValuePair 
`2[System.String,RunTimeBug.Data]' to type 'RunTimeBug.Data'. 
    at System.Linq.Enumerable.<CastIterator>d__b0`1.MoveNext() 
    at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection) 
    at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source) 
    at RunTimeBug.Program.Main(String[] args) 

나는이 기계에서 찾을 수있는 유일한 차이, 그것이 작동하는 경우, CLR 런타임 버전 2.0.50727.4927 기계에 있는지, 그리고 버전 : 프로덕션 서버에서 실행하면 다음과 같은 예외와 함께 실패 2.0.50727.1433이 작동하지 않는 시스템의 경우

캐스트 확장 메서드는 구형 컴퓨터에서 IEnumerable의 잘못된 버전을 가져 오지만 최신 컴퓨터에서는 "올바른"버전입니다.

누구나 내가 이것을보고있는 이유를 설명 할 수 있습니까? 2 CLR 런타임 버전간에 변경된 사항이 원인 일 수 있습니까?

이미 수정 프로그램을 배포했으며 위에 나온 코드의 Collection 클래스는 2 개의 다른 IEnumerable을 구현하므로 디자인이 좋지 않습니다. 이것은 우리 제품의 "야생에서"발견되었으므로 정확한 원인을 알고 싶습니다.

답변

3

Jason이 링크 된 기사에서 언급 된 수정 사항은 이후 릴리스에서 작업하는 코드와 관련이 있다고 생각합니다. Enumerable.Cast SP1 이전 버전에 대한 액세스 권한이 없으므로 추측하기가 어렵습니다.

한 가지 확실한 사실은 코드가 Enumerable.CastIterator()에 들어가면 사용자의 경우에는 작동하지 않을 것이라는 점입니다. IEnumerable을 IEnumerable <>로 변환하는 반복기를 설정하고 반복기는 GetEnumerator()를 호출하여 반복자 블록을 초기화합니다. 그건 당신이 아니라 Dictionary.GetEnumerator() 만 호출 할 수 있습니다. 이 IEnumerable이 Data로 반환하는 KeyValuePair를 캐스팅하면 예외가 발생하므로 물론 실패합니다.

현재 버전의 Enumerable.Cast()는 먼저 IEnumerable을 IEnumerable <>으로 캐스팅하려고합니다. 그리고 그것은 작동합니다. CastIterator()가 사용되지 않습니다.

+0

간단히 말해, 인터페이스를 다시 구현하는 경우 모든 "묶인"멤버를 다시 구현해야합니다. IEnumerable 의 경우 이것은 IEnumerable .GetEnumerator()와 IEnumerable.GetEnumerator()를 모두 구현하는 것을 의미합니다. –

2

"올바른"버전을 선택하는 이유는 무엇이라고 생각하십니까? 개인적으로이 시점에서 모호한 컴파일러 오류가 발생하면 기꺼이 반갑습니다. Cast보다는 오히려 일반 캐스트일까요?

var dataSequence = ((IEnumerable<Data>)coll).ToList(); 

Cast<T>데이터 아닌 가변 캐스트.

현재 각각에 대해 다시 컴파일 하시겠습니까? 문제가 CLR 또는 BCL보다는 컴파일러인지 궁금합니다.

+0

이 상황에서 컴파일러 경고를 선호했을 것입니다. 그러면 "올바른"버전에 대해 이야기 할 때 원래 개발자가 의도 한 버전을 의미했습니다. 한 버전의 프로그램 만 컴파일합니다. 다른 컴퓨터에서 실행되는 동일한 실행 파일입니다. – driis

+0

분명히 올바른 버전의 인터페이스 구현이 여기에 있고, "가장 파생 된"것입니다. –

+0

대부분 무엇을 파생 시켰습니까? 'IEnumerable 'vs'IEnumerable >'둘 다 "파생 된"것이 아닙니다. 논증의 여지가 덜 일반적인 유형의 하나가 더 나은 후보지만, 나는 사양을 매우 신중하게 (또는 신탁 오라클을) 읽을 필요가있을거야. 명시 적 형식화 된 구조체의 경우 –

2

CLR 버전 2.0.50727.1433은 .NET 2.0 SP1이며 CLR 버전 2.0.50727.4927에는 .NET 3.5 SP1이 포함되어 있습니다 (참조 : Version History of the CLR 참조).

Enumerable.Cast의 동작이 here으로 개략적으로 변경되어 .NET 3.5에서 .NET 3.5 SP1로 변경되었습니다.

+0

; 위의 예제는 암시 적 형식화 된 클래스입니다 –

+0

값 형식 변환 문제를 해결하기 위해 동작이 변경되었지만 변경 자체가 참조 형식의 동작을 변경했습니다. 설명을 보려면 nobugz 대답을 참조하십시오. –

관련 문제