为什么 .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);
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您正在尝试将
Dictionary
派生类转换为IEnumerable
。您必须将其转换为IEnumerable>
或从字典传递Values
集合。这不是协方差的问题,而只是类型兼容性的问题。
You're trying to cast
Dictionary<int, T>
-derived class intoIEnumerable<T>
. You have to cast it toIEnumerable<KeyValuePair<int, T>>
or passValues
collection from your dictionaries.This is not a problem with covariance but just with type compatibility.
首先,协/逆变支持是可选的。您需要将限定符
out
或in
添加到泛型类型参数中才能使其正常工作(在接口上,而不是在类上)。因此,您必须:其次,您不能在示例中执行此操作,因为您的参数
T
既是协变的,又是逆变的。为了简化,仅由类返回的类型参数可以是协变的(又名out
),仅由类接受的类型参数是逆变的(又名in
) >)。您的类既接受并返回T
。最后,您的真正问题是
Dictionary
不是IEnumerable
,而是IEnumerable K,V>>
。您需要像这样重写 MyList 上的 GetEnumerator 方法:然后您的示例应该可以工作。
First of all, co-/contravariance support is opt-in. You need to add the qualifiers
out
orin
to a generic type parameter in order for it to work (on an interface, not a class). So you'd have to have:Secondly, you can't do this in your example because your parameter
T
is both co- and contravariant. To simplify, a type parameter that is only returned by a class can be covariant (akaout
), and a type parameter that is only accepted by a class is contravariant (akain
). Your class both accepts and returnsT
.Lastly, your real problem is that
Dictionary<K,V>
isn'tIEnumerable<V>
, butIEnumerable<KeyValuePair<K,V>>
. You'll need to override the GetEnumerator method on MyList like so:Your example should then work.
MyList
间接实现IEnumerable>
(通过Dictionary
),因此它不是与IEnumerable
不兼容。MyList<Car>
indirectly implementsIEnumerable<KeyValuePair<int, Car>>
(viaDictionary<int,Car>
) and so it isn't compatible withIEnumerable<KeyedBase>
.