2011-04-10 5 views
2

나는이 라인에서 컴파일러 오류를 받고 있어요 :이 예제에서 .NET 4.0 공분산이 작동하지 않는 이유는 무엇입니까?

  RenderLookup(Cars); 
      RenderLookup(Employees); 


Error 2 Argument 1: cannot convert from 'Demo.MyList<Demo.Car>' to 'System.Collections.Generic.IEnumerable<Demo.KeyedBase>' Program.cs 85 26 Demo 

Error 4 Argument 1: cannot convert from 'Demo.MyList<Demo.Employee>' to 'System.Collections.Generic.IEnumerable<Demo.KeyedBase>' Program.cs 86 26 Demo 

거래 무엇입니까? 나는 .NET 4.0이 이것을 처리 할 것이라고 생각했다. 내가 뭘 놓치고 있니?

using System; 
using System.Collections.Generic; 

namespace Demo 
{ 
    public interface KeyedBase 
    { 
     int Key { get; } 
     string Description { get; } 
    } 

    public class MyList<T> : Dictionary<int, T> where T : KeyedBase 
    { 
     public void Add(T itm) 
     { 
      Add(itm.Key, itm); 
     } 
    } 

    public class Car : KeyedBase 
    { 
     private readonly int _ID; 
     private readonly string _Description; 
     public Car(int ID, string Description) 
     { 
      _ID = ID; 
      _Description = Description; 
     } 

     public int Key 
     { 
      get { return _ID; } 
     } 

     public string Description 
     { 
      get { return _Description; } 
     } 
    } 

    public class Employee : KeyedBase 
    { 
     private readonly int _ID; 
     private readonly string _FirstName; 
     private readonly string _LastName; 
     public Employee(int ID, string FirstName, string LastName) 
     { 
      _ID = ID; 
      _FirstName = FirstName; 
      _LastName = LastName; 
     } 

     public int Key 
     { 
      get { return _ID; } 
     } 

     public string Description 
     { 
      get { return _LastName + ", " + _FirstName; } 
     } 
    } 

    class Program 
    { 
     private static void RenderLookup(IEnumerable<KeyedBase> Lookup) 
     { 
      Console.WriteLine("Choose:"); 
      foreach (var itm in Lookup) 
      { 
       Console.WriteLine("{0} : {1}", itm.Key, itm.Description); 
      } 
     } 

     static void Main(string[] args) 
     { 
      var Cars = new MyList<Car> { new Car(1, "Subaru"), new Car(2, "Volswagen") }; 

      var Employees = new MyList<Employee> 
           { 
            new Employee(1, "Mickey", "Mouse"), 
            new Employee(2, "Minnie", "Mouse") 
           }; 

      RenderLookup(Cars); 
      RenderLookup(Employees); 
     } 
    } 
} 
+0

오류를 줄 수있는 줄을 알려 주실 수 있습니까? 그것은 더 쉬울 것입니다 ... – Marco

답변

5

우선, 동행/반 환율 지원은 옵트 인입니다. 인터페이스가 아닌 클래스에서 작동하려면 generic 형식 매개 변수에 out 또는 in 한정자를 추가해야합니다. 그래서 당신이해야 할 것 : 당신의 매개 변수 T 모두 공동 contravariant 때문에

interface IMyList<(in/out) T> : ... 

을 두 번째로, 당신은 당신의 예에서이 작업을 수행 할 수 없습니다. 단순화하기 위해 클래스에 의해서만 리턴되는 유형 매개 변수는 공 변 수 (일명 out) 일 수 있으며, 클래스가 허용하는 유형 매개 변수는 반 - 변 수 (일명 in)입니다. 수업은 모두 T을 수락하고 반환합니다.

마지막으로, 당신의 실제 문제는 Dictionary<K,V>IEnumerable<V>하지만 IEnumerable<KeyValuePair<K,V>>되지 않는 것입니다. 다음과 같이 MyList의 GetEnumerator 메서드를 재정의해야합니다.

public class MyList<T> : Dictionary<int, T>, IEnumerable<T> where T : KeyedBase 
{ 
    public void Add(T itm) 
    { 
     Add(itm.Key, itm); 
    } 

    public virtual IEnumerator<T> GetEnumerator() 
    { 
     return Values.GetEnumerator(); 
    } 
} 

예제가 제대로 작동합니다.

+0

+1 (내가 본) – sehe

+0

의 대부분의 indepth 응답 정확히 내가 원하는 것을 수행하는 일반 콜렉션이 있습니다, 나는이 모든 년 후에 그것을 보지 못했습니다 : KeyedCollection (http://msdn.microsoft.com/en-us/library/ms132438(v=VS.100).aspx) –

7

당신은 IEnumerable<T>Dictionary<int, T> 유도 된 클래스를 캐스팅하려고 노력하고 있습니다. 당신은 IEnumerable<KeyValuePair<int, T>>로 캐스팅하거나 사전에서 Values 컬렉션을 전달해야합니다.

RenderLookup(Cars.Values); 
RenderLookup(Employees.Values); 

이 값은 공분산에는 문제가되지 않지만 유형 호환성이 있습니다.

1

MyList<Car>은 (Dictionary<int,Car>을 통해) IEnumerable<KeyValuePair<int, Car>>을 간접적으로 구현하므로 IEnumerable<KeyedBase>과 호환되지 않습니다.

관련 문제