I know how to implement the non generic IEnumerable, like this:
using System;
using System.Collections;
namespace ConsoleApplication33
{
class Program
{
static void Main(string[] args)
{
MyObjects myObjects = new MyObjects();
myObjects[0] = new MyObject() { Foo = "Hello", Bar = 1 };
myObjects[1] = new MyObject() { Foo = "World", Bar = 2 };
foreach (MyObject x in myObjects)
{
Console.WriteLine(x.Foo);
Console.WriteLine(x.Bar);
}
Console.ReadLine();
}
}
class MyObject
{
public string Foo { get; set; }
public int Bar { get; set; }
}
class MyObjects : IEnumerable
{
ArrayList mylist = new ArrayList();
public MyObject this[int index]
{
get { return (MyObject)mylist[index]; }
set { mylist.Insert(index, value); }
}
IEnumerator IEnumerable.GetEnumerator()
{
return mylist.GetEnumerator();
}
}
}
However I also notice that IEnumerable has a generic version, IEnumerable<T>, but I can't figure out how to implement it.
If I add using System.Collections.Generic; to my using directives, and then change:
class MyObjects : IEnumerable
to:
class MyObjects : IEnumerable<MyObject>
And then right click on IEnumerable<MyObject> and select Implement Interface => Implement Interface, Visual Studio helpfully adds the following block of code:
IEnumerator<MyObject> IEnumerable<MyObject>.GetEnumerator()
{
throw new NotImplementedException();
}
Returning the non generic IEnumerable object from the GetEnumerator(); method doesn't work this time, so what do I put here? The CLI now ignores the non generic implementation and heads straight for the generic version when it tries to enumerate through my array during the foreach loop.
If you choose to use a generic collection, such as List<MyObject> instead of ArrayList, you'll find that the List<MyObject> will provide both generic and non-generic enumerators that you can use.
using System.Collections;
class MyObjects : IEnumerable<MyObject>
{
List<MyObject> mylist = new List<MyObject>();
public MyObject this[int index]
{
get { return mylist[index]; }
set { mylist.Insert(index, value); }
}
public IEnumerator<MyObject> GetEnumerator()
{
return mylist.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
You probably do not want an explicit implementation of IEnumerable<T> (which is what you've shown).
The usual pattern is to use IEnumerable<T>'s GetEnumerator in the explicit implementation of IEnumerable:
class FooCollection : IEnumerable<Foo>, IEnumerable
{
SomeCollection<Foo> foos;
// Explicit for IEnumerable because weakly typed collections are Bad
System.Collections.IEnumerator IEnumerable.GetEnumerator()
{
// uses the strongly typed IEnumerable<T> implementation
return this.GetEnumerator();
}
// Normal implementation for IEnumerable<T>
IEnumerator<Foo> GetEnumerator()
{
foreach (Foo foo in this.foos)
{
yield return foo;
//nb: if SomeCollection is not strongly-typed use a cast:
// yield return (Foo)foo;
// Or better yet, switch to an internal collection which is
// strongly-typed. Such as List<T> or T[], your choice.
}
// or, as pointed out: return this.foos.GetEnumerator();
}
}
Why do you do it manually? yield return automates the entire process of handling iterators. (I also wrote about it on my blog, including a look at the compiler generated code).
If you really want to do it yourself, you have to return a generic enumerator too. You won't be able to use an ArrayList any more since that's non-generic. Change it to a List<MyObject> instead. That of course assumes that you only have objects of type MyObject (or derived types) in your collection.
If you work with generics, use List instead of ArrayList. The List has exactly the GetEnumerator method you need.
List<MyObject> myList = new List<MyObject>();
make mylist into a List<MyObject>, is one option
Note that the IEnumerable<T> allready implemented by the System.Collections so another approach is to derive your MyObjects class from System.Collections as a base class (documentation):
System.Collections: Provides the base class for a generic collection.
We can later make our own implemenation to override the virtual System.Collections methods to provide custom behavior (only for ClearItems, InsertItem, RemoveItem, and SetItem along with Equals, GetHashCode, and ToString from Object). Unlike the List<T> which is not designed to be easily extensible.
Example:
public class FooCollection : System.Collections<Foo>
{
//...
protected override void InsertItem(int index, Foo newItem)
{
base.InsertItem(index, newItem);
Console.Write("An item was successfully inserted to MyCollection!");
}
}
public static void Main()
{
FooCollection fooCollection = new FooCollection();
fooCollection.Add(new Foo()); //OUTPUT: An item was successfully inserted to FooCollection!
}
Please note that driving from collection recommended only in case when custom collection behavior is needed, which is rarely happens. see usage.
Related
I have the following code:
public interface ISomeObject
{
IList<ISomeObject> Objects { get; }
}
public class SomeObject : ISomeObject
{
public SomeObject()
{
Objects = new List<SomeObject>();
}
public List<SomeObject> Objects
{
get;
set;
}
IList<ISomeObject> ISomeObject.Objects
{
get
{
// What to do here?
// return Objects; // This doesn't work
return Objects.Cast<ISomeObject>().ToList(); // Works, but creates a copy each time.
}
}
SomeObject has a public property Objects that returns a List of class type. Clients knowing that class type can use that to do whatever they want. Clients only knowing about ISomeObject can use the Objects property only to get an IList<ISomeObject>. Because it is not allowed to cast List<SomeObject> to IList<ISomeObject> (due to the apple and banana issue) I need a way of converting that. The default way, using a Cast.ToList() works, but has the downside that it creates a new List each time the property is evaluated, which may be expensive. Changing ISomeObject.Objects to return an IEnumerable<ISomeObject> has the other downside that the client can't use indexing any more (which is quite relevant in my use case). And using Linq's ElementAt() call repeatedly is expensive, when used on an IEnumerable.
Has anybody got an idea on how to avoid either problem?
(of course, making SomeObject known everywhere is not an option).
You could/should implement a class similar to ReadOnlyCollection<T> to act as a proxy. Considering that it would be read only, it could be "covariant" (not language-side, but logically, meaning that it could proxy a TDest that is a subclass/interface of TSource) and then throw NotSupportedException() for all the write methods.
Something like this (code untested):
public class CovariantReadOlyList<TSource, TDest> : IList<TDest>, IReadOnlyList<TDest> where TSource : class, TDest
{
private readonly IList<TSource> source;
public CovariantReadOlyList(IList<TSource> source)
{
this.source = source;
}
public TDest this[int index] { get => source[index]; set => throw new NotSupportedException(); }
public int Count => source.Count;
public bool IsReadOnly => true;
public void Add(TDest item) => throw new NotSupportedException();
public void Clear() => throw new NotSupportedException();
public bool Contains(TDest item) => IndexOf(item) != -1;
public void CopyTo(TDest[] array, int arrayIndex)
{
// Using the nuget package System.Runtime.CompilerServices.Unsafe
// source.CopyTo(Unsafe.As<TSource[]>(array), arrayIndex);
// We love to play with fire :-)
foreach (TSource ele in source)
{
array[arrayIndex] = ele;
arrayIndex++;
}
}
public IEnumerator<TDest> GetEnumerator() => ((IEnumerable<TDest>)source).GetEnumerator();
public int IndexOf(TDest item)
{
TSource item2 = item as TSource;
if (ReferenceEquals(item2, null) && !ReferenceEquals(item, null))
{
return -1;
}
return source.IndexOf(item2);
}
public void Insert(int index, TDest item)
{
throw new NotSupportedException();
}
public bool Remove(TDest item)
{
throw new NotSupportedException();
}
public void RemoveAt(int index)
{
throw new NotSupportedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Use it like:
IList<string> strs = new List<string>();
IList<object> objs = new CovariantReadOlyList<string, object>(strs);
Changing ISomeObject.Objects to return an IEnumerable<ISomeObject> has the other downside that the client can't use indexing any more (which is quite relevant in my use case).
Indexing isn't just supported by the IList<T> interface, it's also supported by the IReadOnlyList<T> interface. Because IReadOnlyList<T> doesn't allow modification, it can be (and is) covariant just like IEnumerable<T> is.
So, just change the return type to IReadOnlyList<ISomeObject> and return the original list.
Of course, nothing prevents the caller from casting the result to List<SomeObject>, but the caller is supposed to have full access to that list anyway, so there is no security risk.
You may want try to encapsulate your List<SomeObject> making it an implementation detail and return IReadOnlyList<SomeObject> instead. Then SomeObject to ISomeObject cast want be unnecessary in interface implementation as well due to IReadOnlyList variance — you'll be able to return your Objects as IReadOnlyList<ISomeObject> .
Then just add some operations to mutate your underlying list like Add or Remove to container type if those are required.
Also I should mention that interfaces are not so good for restriction — evil consumer can easily cast your ISomeObject to SomeObject and do everything he wants, probably, you should reconsider your design. You'd better stick to such things as immutability and encapsulation for providing usable api. Explicitly use mutable builders then for immutable classes where it's reasonable.
I've implemented the GetEnumerator method for a simple class and was surprised that I couldn't order the enumerator with linq (a call to this.OrderBy(x => x) is invalid). Can someone please explain what's going on here? Am I doing something wrong or are enumerators only intended to be iterated over?
class Test
{
private Dictionary<int, string> dict
= new Dictionary<int, string>();
public IEnumerator<int> GetEnumerator()
{
return dict.Keys.GetEnumerator();
}
public Test()
{
dict[1] = "test";
dict[2] = "nothing";
}
public IEnumerable<int> SortedKeys
{
get { return this.OrderBy(x => x); } // illegal!
}
public void Print()
{
foreach(var key in this)
Console.WriteLine(dict[key]);
}
}
You have to implement the interface IEnumerable<int> in order for the this.OrderBy to work, how else should it know this can enumerate ints?
OrderBy requires this to implement IEnumerable<T>. It doesn't know your GetEnumerator method is actually an attempt to comply to the interface.
foreach just requires a GetEnumerator() method, no interface implementatio needed.
// put in the interface
class Test : IEnumerable<int>
{
private Dictionary<int, string> dict
= new Dictionary<int, string>();
public IEnumerator<int> GetEnumerator()
{
return dict.Keys.GetEnumerator();
}
public Test()
{
dict[1] = "test";
dict[2] = "nothing";
}
public IEnumerable<int> SortedKeys
{
get { return this.OrderBy(x => x); } // illegal!
}
public void Print()
{
foreach (var key in this)
Console.WriteLine(dict[key]);
}
// this one is required according to the interface too
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
An enumerator is an iterator. It's just an interface that tells the runtime or custom code on how to move to a next element in some sequence, reset the iteration to the first element again or get current element in the iteration.
That is, an enumerator isn't enumerable. An enumerable can create an enumerator to let other code enumerate the enumeration.
In order to be able to call a LINQ extension method you need the object to be enumerable. Your Test class doesn't implement IEnumerable<T> (LINQ extension method signatures look like this: public static IEnumerable<T> Whatever<T>(this IEnumerable<T> someEnumerable)).
Since I want to apply DRY principle on myself (Don't Repeat Yourself), if you want to know how to implement IEnumerable<T> you should look at the following Q&A: How do I implement IEnumerable<T>.
OrderBy() is an extension method on IEnumerable<T>.
Your class does not implement IEnumerable<T>.
foreach still works, because it does not require you to implement IEnumerable<T>; it only requires that there is a method GetEnumerator().
So all you need to do is add:
class Test : IEnumerable<int>
and provide the implementation for the non-generic IEnumerable:
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
I have a user defined class that I want to create a public List as part of. I want the List to be a List of delegate functions that I can add to and set each List Member to a delegate function. I want this list of functions to be part of the class I instantiate, so it follows the instance of the class as I pass it to other functions. I need the ability to call the delegated functions via a foreach loop, so it also has to be IEnumberable.
I've been trying for several hours, what I have may or may not do part of the job. When it started looking like I needed to write my own IEnumberation routines for the custom List, I realize I was in way over my head and came here.
This is the code I have:
public delegate List<ChartTestModel> MyDelegate<T>(T i);
public class DelegateList<T>
{
public void Add(MyDelegate<T> del)
{
imp.Add(del);
}
public void CallDelegates(T k)
{
foreach (MyDelegate<T> del in imp)
{
del(k);
}
}
private List<MyDelegate<T>> imp = new List<MyDelegate<T>>();
}
I don't even know if this does what I want it to or not. I know I can't ForEach through it, though. It's written entirely from pieced together code from looking on Google. I barely understand what it's supposed to do.
I don't see why you need a custom class at all. Just use List<T> where T is whatever delegate type.
List<Action> actions = new List<Action>();
actions.Add(() => blah blah);
actions.Add(Whatever); // Whatever() is a method
// now run them all
actions.ForEach(a => a());
IEnumerable<T> is simple to implement, particularly when you have a collection as a member of the class. All you need to do is define appropriate GetEnumerator methods, and the easiest thing to do is return the enumerator of the underlying collection.
class YourClass : IEnumerable<SomeClass>
{
List<SomeClass> list = ...
public IEnumerator<SomeClass> GetEnumerator()
{
return list.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
Here, you implement methods for implicitly for IEnumerable<T> and explicitly for IEnumerable. (You have to implement both as IEnumerable<T> inherits IEnumerable.)
For your specific class, you might have
public class DelegateList<T> : IEnumerable<MyDelegate<T>>
{
// ...other class details
private List<MyDelegate<T>> imp = new List<MyDelegate<T>>();
public IEnumerator<MyDelegate<T>> GetEnumerator()
{
return imp.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
I hope this is userful to you.
static void Main(string[] args)
{
var delegateFuncs = new List<Func<string , string>> {
l1=>{ return "at1:" + l1;} ,
l2=>{ return "at2:" + l2;} ,
l3=>{ return "at3:" + l3;} ,
l4=>{ return "at4:" + l4;}
};
string parameter = "test";
foreach (var f in delegateFuncs)
{
Console.WriteLine(f(parameter));
}
Console.ReadLine();
}
I am developing a collection class, which should implement IEnumerator and IEnumerable.
In my first approach, I implemented them directly. Now I have discovered the yield keyword, and I have been able to simplify everything a whole lot substituting the IEnumerator/IEnumerable interfaces with a readonly property Values that uses yield to return an IEnumerable in a loop.
My question: is it possible to use yield in such a way that I could iterate over the class itself, without implementing IEnumerable/IEnumerator?
I.e., I want to have a functionality similar to the framework collections:
List<int> myList = new List<int>();
foreach (int i in myList)
{
...
}
Is this possible at all?
Update: It seems that my question was badly worded. I don't mind implementing IEnumerator or IEnumerable; I just thought the only way to do it was with the old Current/MoveNext/Reset methods.
You won't have to implement IEnumerable<T> or IEnumerable to get foreach to work - but it would be a good idea to do so. It's very easy to do:
public class Foo : IEnumerable<Bar>
{
public IEnumerator<Bar> GetEnumerator()
{
// Use yield return here, or
// just return Values.GetEnumerator()
}
// Explicit interface implementation for non-generic
// interface; delegates to generic implementation.
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
The alternative which doesn't implement IEnumerable<T> would just call your Values property, but still providing a GetEnumerator() method:
public class Foo
{
public IEnumerator<Bar> GetEnumerator()
{
// Use yield return here, or
// just return Values.GetEnumerator()
}
]
While this will work, it means you won't be able to pass your collection to anything expecting an IEnumerable<T>, such as LINQ to Objects.
It's a little-known fact that foreach will work with any type supporting a GetEnumerator() method which returns a type with appropriate MoveNext() and Current members. This was really to allow strongly-typed collections before generics, where iterating over the collection wouldn't box value types etc. There's really no call for it now, IMO.
You could do somthing like this, but why? IEnumerator is already simple.
Interface MyEnumerator<T>
{
public T GetNext();
}
public static class MyEnumeratorExtender
{
public static void MyForeach<T>(this MyEnumerator<T> enumerator,
Action<T> action)
{
T item = enumerator.GetNext();
while (item != null)
{
action.Invoke(item);
item = enumerator.GetNext();
}
}
}
I'd rather have the in keyword and I wouldn't want to rewrite linq.
I assume the following sample gives a best practice that we should follow when we implement the IEnumerable interface.
https://learn.microsoft.com/en-us/dotnet/api/system.collections.ienumerator.movenext
Here is the question:
Why should we provide two version of Current method?
When the version ONE (object IEnumerator.Current) is used?
When the version TWO (public Person Current ) is used?
How to use PeopleEnum in the foreach statement. // updated
public class PeopleEnum : IEnumerator
{
public Person[] _people;
// Enumerators are positioned before the first element
// until the first MoveNext() call.
int position = -1;
public PeopleEnum(Person[] list)
{
_people = list;
}
public bool MoveNext()
{
position++;
return (position < _people.Length);
}
public void Reset()
{
position = -1;
}
// explicit interface implementation
object IEnumerator.Current /// **version ONE**
{
get
{
return Current;
}
}
public Person Current /// **version TWO**
{
get
{
try
{
return _people[position];
}
catch (IndexOutOfRangeException)
{
throw new InvalidOperationException();
}
}
}
}
The IEnumerator.Current is an explicit interface implementation.
You can only use it if you cast the iterator to an IEnumerator (which is what the framework does with foreach). In other cases, the second version will be used.
You will see that it returns object and actually uses the other implementation which returns a Person.
The second implementation is not required per se by the interface, but is there as a convenience and in order to return the expected type instead of object.
Long-form implementation of IEnumerator is no longer necessary:
public class PeopleEnum : IEnumerable
{
public Person[] _people;
public PeopleEnum(Person[] list)
{
_people = list;
}
public IEnumerator GetEnumerator()
{
foreach (Person person in _people)
yield return person;
}
}
And to further bring it into the 21st century, don't use the non-generic IEnumerable:
public class PeopleEnum : IEnumerable<Person>
{
public Person[] _people;
public PeopleEnum(Person[] list)
{
_people = list;
}
public IEnumerator<Person> GetEnumerator()
{
foreach (Person person in _people)
yield return person;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
I suspect the reason is that this code example was derived from an example class implementing IEnumerator<T> - if the example class PeopleEnum implemented IEnumerator<T> this approach would be required: IEnumerator<T> inherits IEnumerator so you have to implement both interfaces when implementing IEnumerator<T>.
The implementation of the non-generic IEnumerator requires Current to return object - the strongly typed IEnumerator<T> on the other hand requires Current to return an instance of type T - using explicit and direct interface implementation is the only way to fulfill both requirements.
It is there for convenience, eg. using the PeopleEnum.Current in a typesafe way in a while(p.MoveNext()) loop, not explicitly doing a foreach enumeration.
But the only thing you need to do is implement the interface, you could do it implicitly if you wish, however is there a reason for it? If I wanted to use MovePrevious on the class? Would it be cool if I should cast(unbox) the object to Person?
If you think the class could be extended with more manipulation methods the Person Current is a cool thing.
Version two isnt part of the interface. You have to satisfy the interface requirements.