试图强制转换IEnumerable时异常
本文关键字:IEnumerable 异常 转换 | 更新日期: 2023-09-27 18:18:13
我还在为一个项目学习c#的前几周,我正在尝试正确实现IEnumerable
接口。我已经阅读了许多教程/指南,但我似乎仍然在做一些不正确的事情。我有很强的Java背景,所以我认为我对Java泛型的一些知识混淆了我对它们在c#中如何工作的理解。
不能修改的类包含实例变量:
public IEnumerable<object> Items;
我想为它提供我的SampleDataSource
类的一个实例。该类充当MyObject
类型的List
的存储容器:
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();
}
}
但是当我尝试使用以下代码将SampleDataSource
类的实例转换为IEnumerable<object>
时:
Items = (IEnumerable<MyObject>)App.SampleData;
我收到一个异常:
附加信息:无法强制转换类型的对象"Expression.Blend.SampleData.SampleDataSource。SampleDataSource"类型System.Collections.Generic.IEnumerable 1 [Expression.Blend.SampleData.SampleDataSource.MyObject] '。
但我不太明白为什么-不是我的SampleDataSource
作为一个IEnumerable
,返回一个包含MyObject
类型的枚举器?
它不能仅仅实现方法,而必须实际实现接口。
在您的情况下,最好让您的类实现适当的接口。
public class SampleDataSource : IEnumerable<MyObject>, IEnumerable
否则,您可以使用linfu之类的东西将您的类转换为接口。
另一个可能的对象是使用OfType<T>
来处理:
// returns enumerable of the items that are actually assignable to MyObject
IEnumerable<MyObject> values = theDataSource.OfType<MyObject>();
我意识到这个问题已经有了答案,但是我错过了对问题背后问题的简单解释,所以这里是:
不能将SampleDataSource
类分配给IEnumerable<object>
字段的原因是SampleDataSource
没有实现IEnumerable<object>
。虽然它确实实现了IEnumerable
,但这还不够好,因为IEnumerable<object>
是IEnumerable
的子类型。
由于接口协方差,如果MyObject实际上是一个引用类型(即一个类),如果它实现了IEnumerable<MyObject>
,那么您将能够将类分配给IEnumerable<object>
字段。但是,这只适用于c# 4.0及更高版本。
Reed Copsey的回答没有提到您可以这样声明SampleDataSource类,因为IEnumerable<T>
继承自IEnumerable
:
public class SampleDataSource : IEnumerable<MyObject>
此外,由于您只是包装包含的集合,因此您通常会这样实现它:
public class SampleDataSource : IEnumerable<MyObject>
{
public List<MyObject> Subjects { get; private set; }
public IEnumerator<MyObject> GetEnumerator()
{
return Subjects.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
但是,从面向对象的角度来看,这是有问题的,因为您给了列表的公共读写访问权限。(setter是private的这一事实意味着public不能对列表引用重新赋值,但这并不妨碍它们调用列表中的Add
、Remove
或Clear
。)
另一个面向对象的问题是:如果SampleDataSource 包含一个MyObjects序列,为什么它也是一个MyObjects序列?而不是这样做:
classICannotAlter.Items = (IEnumerable<object>)someSampleDataSourceInstance;
也许你应该这样做:
classICannotAlter.Items = (IEnumerable<object>)someSampleDataSourceInstance.Subjects;