我的构建中出现了错误:
错误12无法隐式转换 类型 “System.Collections.Generic.IEnumerator< BaseClass的>” 至 “System.Collections.Generic.IEnumerator< IParentClass>”。 存在显式转换(是你 错过演员?)
简单地把它丢掉是不对的?
这是我的代码:
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!
}
我的问题是,我可以改变这一行:
return this.GetEnumerator();
为:
return (IEnumerator<IParentClass>)this.GetEnumerator();
(没有任何不良副作用)?
接受的答案:
我已将功能更改为以下内容(阅读Jon Skeet的帖子后):
IEnumerator<IParentClass> IEnumerable<IParentClass>.GetEnumerator()
{
return this.Map.Values.Cast<IParentClass>().GetEnumerator();
}
答案 0 :(得分:5)
不,你不能,因为仿制品目前在C#中并不协变。 .NET本身有一些支持(对于委托和接口)但它还没有真正使用过。
如果您要返回IEnumerable<BaseClass>
而不是IEnumerator<BaseClass>
(并假设.NEt 3.5),您可以使用Enumerable.Cast
- 但您目前需要编写自己的扩展方法,例如< / p>
public static IEnumerator<TParent> Upcast<TParent, TChild>
(this IEnumerator<TChild> source)
where TChild : TParent
{
while (source.MoveNext())
{
yield return source.Current;
}
}
或者在你的情况下你可以使用Cast:
return this.Map.Values.Cast<BaseClass>().GetEnumerator();
答案 1 :(得分:2)
不,你不能,至少在C#3.0及以下界面方差不受支持。请参阅Eric Lippert关于此的精彩系列,特别是this one。
答案 2 :(得分:0)
IEnumerator<BaseClass>
和IEnumerator<ParentClass>
是无关的,尽管它们的通用参数是。我会改为使用LINQ Select
扩展方法:
return this.Select(x => (IParentClass)x).GetEnumerator();
或Cast
扩展方法:
return this.Cast<IParentClass>().GetEnumerator();
答案 3 :(得分:0)
不,它不安全,见下文:
使用System.Collections.Generic; Foo {} class Bar: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
}
}
但是,你应该能够使用迭代器块为你做演员吗?
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;
}
}
}
答案 4 :(得分:0)
要理解为什么这是不合适的,请拍照而不是Enumerator
,List
。两者都使用泛型 - 编译器不会以与通用参数相关的特殊方式处理任何一个。
void doStuff() {
List<IParentThing> list = getList();
list.add(new ChildThing2());
}
List<IParentThing> getList() {
return new List<ChildThing1>(); //ERROR!
}
第一种方法很好 - IParentThing
的列表应该能够接收ChildThing2
。但是ChildThing1
的列表无法处理ChildThing2
,或者IParentThing
除了ChildThing1
以外的任何实现者 - 换句话说,如果允许List<ChildThing1>
要转换为List<IParent>
,它必须能够处理IParentThing
的所有子类,而不仅仅是IParentThing
和ChildThing1
。< / p>
请注意,Java泛型有一种方式可以说“我想要一个从此继承的东西的列表”,除了“我想要一个这个继承的东西的列表”,这样可以让我更有意思(在我看来)优雅)解决一些问题。