【问题标题】:Exception when attempting to cast IEnumerable?尝试强制转换 IEnumerable 时出现异常?
【发布时间】:2011-12-16 00:29:06
【问题描述】:

我还在为一个项目学习 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&lt;object&gt; 时:

Items = (IEnumerable<MyObject>)App.SampleData;

我收到一个异常:

附加信息:无法转换类型的对象 'Expression.Blend.SampleData.SampleDataSource.SampleDataSource' 到 类型 'System.Collections.Generic.IEnumerable`1[Expression.Blend.SampleData.SampleDataSource.MyObject]'。

但我不太明白为什么 - 我的 SampleDataSource 不是正确地充当返回包含 MyObject 类型的枚举器的 IEnumerable 吗?

【问题讨论】:

    标签: c# generics casting ienumerable


    【解决方案1】:

    它不能只实现方法,而是必须实际实现接口。

    在您的情况下,最好让您的类实现适当的接口。

    public class SampleDataSource : IEnumerable<MyObject>, IEnumerable
    

    否则,您可以使用linfu 之类的东西将您的类直接输入到界面中。

    另一个潜在的对象是使用OfType&lt;T&gt; 来处理这个:

    // returns enumerable of the items that are actually assignable to MyObject
    IEnumerable<MyObject> values = theDataSource.OfType<MyObject>();
    

    【讨论】:

    • 你能说得更具体点吗?是不是这里没有正确实现接口:SampleDataSource : IEnumerable?
    • @craig 需要实现IEnumerable&lt;MyObject&gt;
    • @craig 你想得到IEnumerable&lt;object&gt; 还是IEnumerable&lt;MyObject&gt;
    • 啊,这确实是问题所在,必须在我正在实现的接口中添加类型声明。 (除了实现 IEnumerable 接口并定义了 oa 类型。)我正在尝试将此类的一个实例分配给一个期望 IEnumerable&lt;object&gt; 的变量我仍在实现您的解决方案,但我会一秒钟后返回接受。 :)
    【解决方案2】:

    我知道这个问题已经回答了,但是我错过了对你问题背后问题的简单解释,所以这里是:

    您不能将SampleDataSource 类分配给IEnumerable&lt;object&gt; 字段的原因是SampleDataSource 没有实现IEnumerable&lt;object&gt;。虽然它确实实现了IEnumerable,但这还不够好,因为IEnumerable&lt;object&gt;IEnumerable子类型

    由于接口协变,如果 MyObject 实际上是一个引用类型(即类)。不过,这只适用于 C# 4.0 及更高版本。

    Reed Copsey 的回答没有提到您可以这样声明 SampleDataSource 类,因为 IEnumerable&lt;T&gt; 继承自 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;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-06
      相关资源
      最近更新 更多