C# 将子类的枚举数强制转换为父类的枚举数是否错误?
我的构建中有一个错误,上面写着: 错误12无法隐式转换 类型 'System.Collections.Generic.IEnumeratorC# 将子类的枚举数强制转换为父类的枚举数是否错误?,c#,.net,generics,covariance,C#,.net,Generics,Covariance,我的构建中有一个错误,上面写着: 错误12无法隐式转换 类型 'System.Collections.Generic.IEnumerator' 到 “System.Collections.Generic.IEnumerator”。 存在一个显式转换(您是吗 缺少演员阵容?) 简单地抛弃它是错误的吗 这是我的代码: public Dictionary<Int32, BaseClass> Map { get; private set; } public IEnumerator<B
public Dictionary<Int32, BaseClass> Map { get; private set; }
public IEnumerator<BaseClass> GetEnumerator()
{
return this.Map.Values.GetEnumerator();
}
public IEnumerator<IParentClass> IEnumerable<IParentClass>.GetEnumerator()
{
return this.GetEnumerator(); // ERROR!
}
致:
返回(IEnumerator)this.GetEnumerator();
(没有任何不良副作用)
接受答案:我已将函数更改为以下内容(在阅读Jon Skeet的帖子后):
IEnumerator IEnumerable.GetEnumerator()
{
返回此.Map.Values.Cast().GetEnumerator();
}
IEnumerator
和IEnumerator
是不相关的,尽管它们的通用参数是。我将改为使用LINQSelect
扩展方法,如下所示:
return this.Select(x => (IParentClass)x).GetEnumerator();
或Cast
扩展方法:
return this.Cast<IParentClass>().GetEnumerator();
返回此.Cast().GetEnumerator();
不,您不能,至少在C#3.0及以下版本中,不支持界面差异。请参阅Eric Lippert在这方面的优秀系列,尤其是。不,你不能,因为泛型在C#中目前是不协变的。NET本身有一些支持(对于委托和接口),但它还没有真正被使用
如果返回的是IEnumerable
,而不是IEnumerator
(并假设为.NEt 3.5),则可以使用Enumerable.Cast
——但当前需要编写自己的扩展方法,例如
public static IEnumerator<TParent> Upcast<TParent, TChild>
(this IEnumerator<TChild> source)
where TChild : TParent
{
while (source.MoveNext())
{
yield return source.Current;
}
}
公共静态IEnumerator向上广播
(此IEnumerator来源)
TChild:t租金在哪里
{
while(source.MoveNext())
{
产生返回源。电流;
}
}
或者,在您的情况下,您可以更早地使用Cast:
return this.Map.Values.Cast<BaseClass>().GetEnumerator();
返回此.Map.Values.Cast().GetEnumerator();
不,它不安全,请参见以下内容:
使用System.Collections.Generic;
类Foo{}
类栏:Foo{}
static class Program
{
static IEnumerator<Foo> GetBase() {
yield return new Foo();
yield return new Bar();
}
static IEnumerator<Bar> GetDerived()
{
return (IEnumerator<Bar>)GetBase();
}
static void Main()
{
var obj = GetDerived(); // EXCEPTION
}
}
静态类程序
{
静态IEnumerator GetBase(){
返回新Foo();
屈服返回新棒();
}
静态IEnumerator get派生()
{
返回(IEnumerator)GetBase();
}
静态void Main()
{
var obj=get派生();//异常
}
}
但是,您应该能够使用迭代器块为您执行强制转换
static IEnumerator<Bar> GetDerived()
{
using (IEnumerator<Foo> e = GetBase())
{
while (e.MoveNext())
{
// or use "as" and only return valid data
yield return (Bar)e.Current;
}
}
}
静态IEnumerator get派生()
{
使用(IEnumerator e=GetBase())
{
while(如MoveNext())
{
//或者使用“as”并仅返回有效数据
收益率返回(巴)e.电流;
}
}
}
要解释这不合适的原因,请使用图片而不是枚举器、列表。两者都使用泛型-编译器不会以与泛型参数相关的特殊方式处理任何一个
void doStuff() {
List<IParentThing> list = getList();
list.add(new ChildThing2());
}
List<IParentThing> getList() {
return new List<ChildThing1>(); //ERROR!
}
void doStuff(){
List=getList();
添加(新的ChildThing2());
}
List getList(){
返回新列表();//错误!
}
第一种方法很好-一个iparenthing
s列表应该能够接收ChildThing2
。但是ChildThing1
s列表不能处理ChildThing2
,或者实际上不能处理iparenthing
以外的ChildThing1
的任何实现者-换句话说,如果ListChildThing1>
被允许转换为ListIParent>
,它必须能够处理iparenthing
的所有子类,而不仅仅是iparenthing
和ChildThing1
请注意,Java泛型有一种说法,除了“我想要一个由此继承的任何东西的列表”之外,“我想要一个由此继承的任何东西的列表”,这允许对一些问题提供更有趣(而且在我看来是优雅的)的解决方案。IEnumerator不行——您需要IEnumerable。(在这种情况下,首先使用Cast())我已经更正了这个示例。我还包括Cast()方法。
static class Program
{
static IEnumerator<Foo> GetBase() {
yield return new Foo();
yield return new Bar();
}
static IEnumerator<Bar> GetDerived()
{
return (IEnumerator<Bar>)GetBase();
}
static void Main()
{
var obj = GetDerived(); // EXCEPTION
}
}
static IEnumerator<Bar> GetDerived()
{
using (IEnumerator<Foo> e = GetBase())
{
while (e.MoveNext())
{
// or use "as" and only return valid data
yield return (Bar)e.Current;
}
}
}
void doStuff() {
List<IParentThing> list = getList();
list.add(new ChildThing2());
}
List<IParentThing> getList() {
return new List<ChildThing1>(); //ERROR!
}