Exception when trying to throw IEnumerable?

I'm still in the first couple of weeks of learning C # for a project, and I'm trying to correctly implement the IEnumerable interface. I read a few manuals / manuals, but I still seem to be doing something wrong. I have a strong Java background, so I think some of my knowledge of Java generics confuses my understanding of how they work in C #.

A class that I cannot change contains an instance variable:

public IEnumerable<object> Items;

And I would like to provide it with an instance of my SampleDataSource class. This class acts as a storage container for the 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 try to apply an instance of this SampleDataSource class to an IEnumerable<object> using this code:

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

I get an exception:

Additional Information: It is not possible to create an 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 - not my SampleDataSource , acting as an IEnumerable that returns an enumerator containing MyObject types?

+4
source share
2 answers

It cannot just implement the methods, but must actually implement the interface.

In your case, it would be better to just make your class an implementation of the corresponding interface.

 public class SampleDataSource : IEnumerable<MyObject>, IEnumerable 

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

Another 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>(); 
+6
source

I understand that this question has already been answered, but I missed a simple explanation of the problem behind your question, so it says here:

The reason you cannot assign the SampleDataSource class to the IEnumerable<object> field is because SampleDataSource does not implement IEnumerable<object> . Although it implements IEnumerable , it is not very good because IEnumerable<object> is a subtype of IEnumerable .

Due to covariance of the interface, you can assign a class to the IEnumerable<object> field if it implements IEnumerable<MyObject> , provided that MyObject is actually a reference type (i.e. a class). However, this only applies to C # 4.0 and later.

Reed Copsey's answer does not mention that you can declare a SampleDataSource class this way because IEnumerable<T> inherits from IEnumerable :

 public class SampleDataSource : IEnumerable<MyObject> 

Also, since you just wrap the contained collection, you usually implement it this way:

 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 doubtful from the point of view of object orientation, because, since you provide public access for reading and writing to the list. (The fact that the setter is closed means that the public cannot reassign the link to the list, but this does not stop them from calling Add or Remove or Clear in the list.)

Another object orientation question is to ask: if the SampleDataSource contains the sequence MyObjects, why will it also be the sequence MyObjects? Instead of this:

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

maybe you should do this:

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

Source: https://habr.com/ru/post/1386619/


All Articles