[英]Exception when attempting to cast IEnumerable?
I'm still in my first couple weeks of learning C# for a project, and I'm trying to properly implement the IEnumerable
interface. 我还在学习C#项目的前几周,我正在尝试正确实现
IEnumerable
接口。 I've read a number of tutorials/guidelines, but I still seem to be doing something incorrectly. 我已经阅读了许多教程/指南,但我似乎仍然做错了什么。 I have a strong Java background, so I think some of my knowledge of Java generics is muddling my understanding how they work in C#.
我有一个强大的Java背景,所以我认为我对Java泛型的一些知识让我理解它们如何在C#中工作。
A class that I cannot alter contains an instance variable: 我无法改变的类包含一个实例变量:
public IEnumerable<object> Items;
And I'd like to provide it with an instance of my SampleDataSource
class. 我想为它提供一个
SampleDataSource
类的实例。 This class acts as a storage container for a List
of MyObject
types: 此类充当
List
of MyObject
类型的存储容器:
public class SampleDataSource : IEnumerable
{
public List<MyObject> Subjects { get; private set; }
public IEnumerator<MyObject> GetEnumerator()
{
return this.Cast<MyObject>().GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
But when I attempt to cast an instance of this SampleDataSource
class to an IEnumerable<object>
using this code: 但是当我尝试使用此代码将此
SampleDataSource
类的实例 SampleDataSource
转换为IEnumerable<object>
:
Items = (IEnumerable<MyObject>)App.SampleData;
I receive an exception: 我收到一个例外:
Additional information: Unable to cast object of type 'Expression.Blend.SampleData.SampleDataSource.SampleDataSource' to type 'System.Collections.Generic.IEnumerable`1[Expression.Blend.SampleData.SampleDataSource.MyObject]'.
附加信息:无法将类型为“Expression.Blend.SampleData.SampleDataSource.SampleDataSource”的对象强制转换为'System.Collections.Generic.IEnumerable`1 [Expression.Blend.SampleData.SampleDataSource.MyObject]'。
But I don't quite understand why - isn't my SampleDataSource
properly acting as an IEnumerable
that returns an enumerator containing MyObject
types? 但我不太明白为什么 - 我的
SampleDataSource
是否正确地作为IEnumerable
正在返回包含MyObject
类型的枚举器?
It can't just implement the methods, but rather has to actually implement the interface. 它不仅可以实现方法,而且必须实际实现接口。
In your case, it'd be better to just make your class implement the appropriate interface. 在你的情况下,最好让你的类实现适当的接口。
public class SampleDataSource : IEnumerable<MyObject>, IEnumerable
Otherwise, you can use something like linfu to duck-type your class to the interface. 否则,你可以使用像linfu这样的东西将你的类打包到接口。
The other potential object is to use OfType<T>
to handle this: 另一个潜在的对象是使用
OfType<T>
来处理这个:
// returns enumerable of the items that are actually assignable to MyObject
IEnumerable<MyObject> values = theDataSource.OfType<MyObject>();
I realize the question is answered already, but I missed a simple explanation of the problem behind your question, so here goes: 我已经意识到这个问题已经回答了,但是我错过了对你问题背后问题的一个简单解释,所以这里有:
The reason you cannot assign your SampleDataSource
class to an IEnumerable<object>
field is that SampleDataSource
does not implement IEnumerable<object>
. 您无法将
SampleDataSource
类分配给IEnumerable<object>
字段的原因是SampleDataSource
不实现IEnumerable<object>
。 While it does implement IEnumerable
, that's not good enough, because IEnumerable<object>
is a subtype of IEnumerable
. 虽然它确实实现了
IEnumerable
,但这还不够好,因为IEnumerable<object>
是IEnumerable
的子类型 。
Because of interface covariance, you will be able to assign the class to the IEnumerable<object>
field if it implements IEnumerable<MyObject>
, provided that MyObject is in fact a reference type (ie, a class). 由于接口协方差,如果它实现
IEnumerable<MyObject>
,您将能够将类分配给IEnumerable<object>
字段,前提是MyObject实际上是引用类型(即类)。 That's only applicable to C# 4.0 and later, however. 但是,这仅适用于C#4.0及更高版本。
Reed Copsey's answer doesn't mention that you could declare the SampleDataSource class thus, because IEnumerable<T>
inherits from IEnumerable
: Reed Copsey的回答没有提到你可以声明SampleDataSource类,因为
IEnumerable<T>
继承自IEnumerable
:
public class SampleDataSource : IEnumerable<MyObject>
Further, since you're just wrapping the contained collection, you would normally implement it thus: 此外,由于您只是包装所包含的集合,因此通常会实现它:
public class SampleDataSource : IEnumerable<MyObject>
{
public List<MyObject> Subjects { get; private set; }
public IEnumerator<MyObject> GetEnumerator()
{
return Subjects.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
This is questionable from an object-orientation perspective, though, since you're giving the public read-write access to the list. 但是,从面向对象的角度来看,这是有问题的,因为您正在为列表提供公共读写访问权限。 (The fact that the setter is private means that the public can't reassign the list reference, but it doesn't prevent them from calling
Add
or Remove
or Clear
on the list.) (setter是私有的这一事实意味着公众不能重新分配列表引用,但它不会阻止它们在列表上调用
Add
或Remove
或Clear
。)
Another take on the object orientation question would be to ask: if a SampleDataSource contains a sequence of MyObjects, why would it also be a sequence of MyObjects? 另取在面向对象的问题是要问:如果一个SampleDataSource 包含 MyObjects序列,为什么会也是 MyObjects的序列? Instead of doing this:
而不是这样做:
classICannotAlter.Items = (IEnumerable<object>)someSampleDataSourceInstance;
maybe you should be doing this: 也许你应该这样做:
classICannotAlter.Items = (IEnumerable<object>)someSampleDataSourceInstance.Subjects;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.