我还在学习C#项目的前几周,我正在尝试正确实现IEnumerable
接口。我已经阅读了许多教程/指南,但我似乎仍然做错了什么。我有一个强大的Java背景,所以我认为我对Java泛型的一些知识让我理解它们在C#中是如何工作的。
我无法改变的类包含一个实例变量:
public IEnumerable<object> Items;
我想为它提供我的SampleDataSource
课程的实例。此类充当List
个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();
}
}
但是当我尝试使用此代码将此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
类型的枚举数?
答案 0 :(得分:6)
它不仅可以实现方法,而且必须实际实现接口。
在您的情况下,最好让您的类实现适当的接口。
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>();
答案 1 :(得分:1)
我意识到这个问题已经回答了,但是我错过了对你问题背后问题的一个简单解释,所以这里有:
您无法将SampleDataSource
班级分配到IEnumerable<object>
字段的原因是SampleDataSource
未实施IEnumerable<object>
。虽然它确实实现了IEnumerable
,但这还不够好,因为IEnumerable<object>
是IEnumerable
的子类型。
由于接口协方差,如果MyObject实际上是一个引用类型,将 能够将类分配给IEnumerable<object>
字段(如果它实现IEnumerable<MyObject>
)即一类)。但是,这仅适用于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是私有的这一事实意味着公众无法重新分配列表引用,但这并不妨碍他们调用列表中的Add
或Remove
或Clear
。 )
面向对象问题的另一个问题是:如果SampleDataSource 包含一系列MyObjects,为什么它 是一个MyObjects序列?而不是这样做:
classICannotAlter.Items = (IEnumerable<object>)someSampleDataSourceInstance;
也许你应该这样做:
classICannotAlter.Items = (IEnumerable<object>)someSampleDataSourceInstance.Subjects;