尝试转换IEnumerable时出现异常?

时间:2011-12-16 00:29:07

标签: c# generics casting ienumerable

我还在学习C#项目的前几周,我正在尝试正确实现IEnumerable接口。我已经阅读了许多教程/指南,但我似乎仍然做错了什么。我有一个强大的Java背景,所以我认为我对Java泛型的一些知识让我理解它们在C#中是如何工作的。

我无法改变的类包含一个实例变量:

public IEnumerable<object> Items;

我想为它提供我的SampleDataSource课程的实例。此类充当ListMyObject类型的存储容器:

    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类型的枚举数?

2 个答案:

答案 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是私有的这一事实意味着公众无法重新分配列表引用,但这并不妨碍他们调用列表中的AddRemoveClear。 )

面向对象问题的另一个问题是:如果SampleDataSource 包含一系列MyObjects,为什么它 是一个MyObjects序列?而不是这样做:

classICannotAlter.Items = (IEnumerable<object>)someSampleDataSourceInstance;

也许你应该这样做:

classICannotAlter.Items = (IEnumerable<object>)someSampleDataSourceInstance.Subjects;