繁体   English   中英

尝试转换IEnumerable时出现异常?

[英]Exception when attempting to cast IEnumerable?

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

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

public IEnumerable<object> Items;

我想为它提供一个SampleDataSource类的实例。 此类充当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();
        }
    }

但是当我尝试使用此代码将此SampleDataSource的实例 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子类型

由于接口协方差,如果它实现IEnumerable<MyObject> ,您能够将类分配给IEnumerable<object>字段,前提是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;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM