试图强制转换IEnumerable时异常



我还在为一个项目学习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不能对列表引用重新赋值,但这并不妨碍它们调用列表中的AddRemoveClear。) 另一个面向对象的问题是:如果SampleDataSource 包含一个MyObjects序列,为什么它也一个MyObjects序列?而不是这样做:
classICannotAlter.Items = (IEnumerable<object>)someSampleDataSourceInstance;

也许你应该这样做:

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

相关内容

最新更新