我在这些行上遇到了编译器错误:
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 :(得分:7)
您正在尝试将Dictionary<int, T>
派生类转换为IEnumerable<T>
。您必须将其转换为IEnumerable<KeyValuePair<int, T>>
或从您的词典中传递Values
集合。
RenderLookup(Cars.Values);
RenderLookup(Employees.Values);
这不是协方差的问题,而是与类型兼容性有关。
答案 1 :(得分:5)
首先,共同/逆转支持是选择加入。您需要将限定符out
或in
添加到泛型类型参数,以使其起作用(在接口上,而不是类)。所以你必须要:
interface IMyList<(in/out) T> : ...
其次,您无法在示例中执行此操作,因为您的参数T
同时是co- 和逆变。为简化起见,仅由类返回的类型参数可以是协变的(aka out
),并且只有类接受的类型参数是逆变的(aka 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();
}
}
然后你的例子应该有效。
答案 2 :(得分:1)
MyList<Car>
间接实施IEnumerable<KeyValuePair<int, Car>>
(通过Dictionary<int,Car>
),因此与IEnumerable<KeyedBase>
不兼容。