尝试强制转换 IEnumerable 时出现异常?

发布于 2024-12-21 06:34:33 字数 1339 浏览 3 评论 0原文

我仍处于为项目学习 C# 的前几周,并且正在尝试正确实现 IEnumerable 接口。我已经阅读了许多教程/指南,但我似乎仍然做错了一些事情。我有很强的 Java 背景,所以我认为我对 Java 泛型的一些了解混淆了我对它们在 C# 中如何工作的理解。

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

public IEnumerable; 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< 的实例时使用以下代码将 /code> 类转换为 IEnumerable

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

我收到异常:

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

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

I'm still in my first couple weeks of learning C# for a project, and I'm trying to properly implement the IEnumerable interface. I've read a number of tutorials/guidelines, but I still seem to be doing something incorrectly. I have a strong Java background, so I think some of my knowledge of Java generics is muddling my understanding how they work in C#.

A class that I cannot alter contains an instance variable:

public IEnumerable<object> Items;

And I'd like to provide it with an instance of my SampleDataSource class. This class acts as a storage container for a List of MyObject types:

    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();
        }
    }

But when I attempt to cast an instance of this SampleDataSource class to an IEnumerable<object> using this code:

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

I receive an exception:

Additional information: Unable to cast object of type
'Expression.Blend.SampleData.SampleDataSource.SampleDataSource' to
type
'System.Collections.Generic.IEnumerable`1[Expression.Blend.SampleData.SampleDataSource.MyObject]'.

But I don't quite understand why - isn't my SampleDataSource properly acting as an IEnumerable that returns an enumerator containing MyObject types?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

半仙 2024-12-28 06:34:33

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

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

public class SampleDataSource : IEnumerable<MyObject>, IEnumerable

否则,您可以使用 linfu 之类的方法将您的类鸭式输入到接口中。

另一个潜在的对象是使用 OfType 来处理此问题:

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

It can't just implement the methods, but rather has to actually implement the interface.

In your case, it'd be better to just make your class implement the appropriate interface.

public class SampleDataSource : IEnumerable<MyObject>, IEnumerable

Otherwise, you can use something like linfu to duck-type your class to the interface.

The other potential object is to use OfType<T> to handle this:

// returns enumerable of the items that are actually assignable to MyObject
IEnumerable<MyObject> values = theDataSource.OfType<MyObject>();
陈年往事 2024-12-28 06:34:33

我意识到问题已经得到解答,但我错过了问题背后问题的简单解释,所以这里是:

您无法将 SampleDataSource 类分配给 IEnumerable< 的原因/code> 字段的问题是 SampleDataSource 未实现 IEnumerable。虽然它确实实现了 IEnumerable,但这还不够好,因为 IEnumerableIEnumerable子类型

由于接口协变,如果该类实现了 IEnumerable,您能够将该类分配给 IEnumerable字段,前提是该类实现了 IEnumerable MyObject 实际上是一个引用类型(即一个类)。不过,这仅适用于 C# 4.0 及更高版本。

Reed Copsey 的答案没有提到您可以这样声明 SampleDataSource 类,因为 IEnumerable 继承自 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 是私有的,这意味着公众无法重新分配列表引用,但这并不能阻止他们调用 AddRemove清除列表上的。)

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

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

也许你应该这样做:

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

I realize the question is answered already, but I missed a simple explanation of the problem behind your question, so here goes:

The reason you cannot assign your SampleDataSource class to an IEnumerable<object> field is that SampleDataSource does not implement IEnumerable<object>. While it does implement IEnumerable, that's not good enough, because IEnumerable<object> is a subtype of IEnumerable.

Because of interface covariance, you will be able to assign the class to the IEnumerable<object> field if it implements IEnumerable<MyObject>, provided that MyObject is in fact a reference type (i.e., a class). That's only applicable to C# 4.0 and later, however.

Reed Copsey's answer doesn't mention that you could declare the SampleDataSource class thus, because IEnumerable<T> inherits from IEnumerable:

public class SampleDataSource : IEnumerable<MyObject>

Further, since you're just wrapping the contained collection, you would normally implement it thus:

public class SampleDataSource : IEnumerable<MyObject>
{  
    public List<MyObject> Subjects { get; private set; }  

    public IEnumerator<MyObject> GetEnumerator()  
    {  
        return Subjects.GetEnumerator();
    }  

    IEnumerator IEnumerable.GetEnumerator()  
    {  
        return GetEnumerator();  
    }  
}  

This is questionable from an object-orientation perspective, though, since you're giving the public read-write access to the list. (The fact that the setter is private means that the public can't reassign the list reference, but it doesn't prevent them from calling Add or Remove or Clear on the list.)

Another take on the object orientation question would be to ask: if a SampleDataSource contains a sequence of MyObjects, why would it also be a sequence of MyObjects? Instead of doing this:

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

maybe you should be doing this:

classICannotAlter.Items = (IEnumerable<object>)someSampleDataSourceInstance.Subjects;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文