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();
}
Related
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();
}
This code is not compiling, and it's throwing the following error:
The type 'TestesInterfaces.MyCollection' already contains a definition for 'Current'
But when I delete the ambiguous method, it keeps giving other errors.
Can anyone help?
public class MyCollection<T> : IEnumerator<T>
{
private T[] vector = new T[1000];
private int actualIndex;
public void Add(T elemento)
{
this.vector[vector.Length] = elemento;
}
public bool MoveNext()
{
actualIndex++;
return (vector.Length > actualIndex);
}
public void Reset()
{
actualIndex = -1;
}
void IDisposable.Dispose() { }
public Object Current
{
get
{
return Current;
}
}
public T Current
{
get
{
try
{
T element = vector[actualIndex];
return element;
}
catch (IndexOutOfRangeException e)
{
throw new InvalidOperationException(e.Message);
}
}
}
}
I think you're misunderstanding IEnumerator<T>. Typically, collections implement IEnumerable<T>, not IEnumerator<T>. You can think of them like this:
When a class implements IEnumerable<T>, it is stating "I am a collection of things that can be enumerated."
When a class implements IEnumerator<T>, it is stating "I am a thing that enumerates over something."
It is rare (and probably wrong) for a collection to implement IEnumerator<T>. By doing so, you're limiting your collection to a single enumeration. If you try to loop through the collection within a segment of code that's already looping through the collection, or if you try to loop through the collection on multiple threads simultaneously, you won't be able to do it because your collection is itself storing the state of the enumeration operation. Typically, collections (implementing IEnumerable<T>) return a separate object (implementing IEnumerator<T>) and that separate object is responsible for storing the state of the enumeration operation. Therefore, you can have any number of concurrent or nested enumerations because each enumeration operation is represented by a distinct object.
Also, in order for the foreach statement to work, the object after the in keyword, must implement IEnumerable or IEnumerable<T>. It will not work if the object only implements IEnumerator or IEnumerator<T>.
I believe this is the code you're looking for:
public class MyCollection<T> : IEnumerable<T>
{
private T[] vector = new T[1000];
private int count;
public void Add(T elemento)
{
this.vector[count++] = elemento;
}
public IEnumerator<T> GetEnumerator()
{
return vector.Take(count).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
You need to define the interface the current is implementing.
Object IEnumerator.Current
{
//
}
public T Current
{
//
}
This way your class has 2 Current properties. but you can access them both.
MyCollection<string> col = new MyCollection<string>();
var ienumeratort = col.Current; //Uses IEnumerator<T>
var ienumerator = (IEnumerator)col.Current; //uses IEnumerator
I think with C# 2.0 onwards, you have a very easy way of implementing iterator and compiler does a lot of heavy lifting behind the scene by creating state machine. It's worth looking into it. Having said that, in that case your implementation would look something below:
public class MyCollection<T>
{
private T[] vector = new T[1000];
private int actualIndex;
public void Add(T elemento)
{
this.vector[vector.Length] = elemento;
}
public IEnumerable<T> CreateEnumerable()
{
for (int index = 0; index < vector.Length; index++)
{
yield return vector[(index + actualIndex)];
}
}
}
I am not sure about the purpose of actualIndex though - but i hope you get the idea.
After proper initialization of MyCollection, below is snippet somewhat looks like from consumer perspective:
MyCollection<int> mycoll = new MyCollection<int>();
foreach (var num in mycoll.CreateEnumerable())
{
Console.WriteLine(num);
}
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.
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 need help making this method generic. It is repeated about ten times to get lists for different web list controls (substituting "MyType" for the type used in the particular control).
private static IList<MyType> GetList(RequestForm form)
{
// get base list
IMyTypeRepository myTypeRepository = new MyTypeRepository(new HybridSessionBuilder());
IList<MyType> myTypes = myTypeRepository.GetAll();
// create results list
IList<MyType> result = new List<MyType>();
// iterate for active + used list items
foreach (MyType myType in myTypes)
{
if (myType.Active || form.SolutionType.Contains(myType.Value))
{
result.Add(myType);
}
}
// return sorted results
result.OrderBy(o => o.DisplayOrder);
return result;
}
Let me know if this isn't enough information. I think this requires more advanced language features that I'm just getting acquainted with. Maybe I should make them all use the same repository?
Thanks for your help.
EDIT:
Thanks for your help. I don't have any peer support, so this board is fantastic and I learned something from each of you. I wish I could accept all the answers.
You could firstly make your function a bit more terse like this:
private static IList<MyType> GetList(RequestForm form)
{
// get base list
IMyTypeRepository myTypeRepository =
new MyTypeRepository(new HybridSessionBuilder());
IList<MyType> myTypes = myTypeRepository.GetAll();
return myTypes.Where(x => x.Active || form.SolutionType.Contains(x.Value))
.OrderBy(x => x.DisplayOrder).ToList();
}
At that point, most of the content of the function is directly related to MyType, so how you can further improve it depends largely on how MyType relates to the other types involved. For example, here is a hypothetical version that you could write if your other types followed a reasonable-looking (to me) contract:
private static IList<T> GetList(RequestForm form) where T : OrderedValueContainer
{
// we'll want to somehow genericize the idea of a TypeRepository that can
// produce these types; if that can't be done, we're probably better off
// passing a repository into this function rather than creating it here
var repository = new TypeRepository<T>(new HybridSessionBuilder());
IList<T> myTypes = repository.GetAll();
// the hypothetical OrderedValueContainer class/interface
// contains definitions for Active, Value, and DisplayOrder
return myTypes.Where(x => x.Active || form.SolutionType.Contains(x.Value))
.OrderBy(x => x.DisplayOrder).ToList();
}
If all the types implement the same interface, (if they don't then make them, and make sure to add all the properties to the interface that are needed in this method) then you can do something like this:
private static IList<T> GetList(RequestForm form)
where T: IMyInterface
{
// get base list
IMyTypeRepository myTypeRepository = new MyTypeRepository(new HybridSessionBuilder());
IList<T> myTypes = myTypeRepository.GetAll();
// create results list
IList<T> result = new List<T>();
// iterate for active + used list items
foreach (T myType in myTypes)
{
if (myType.Active || form.SolutionType.Contains(myType.Value))
{
result.Add(myType);
}
}
// return sorted results
return result.OrderBy(o => o.DisplayOrder).ToList();
}
One other change I made is the last line, where you had the orderby on a seperate line and were never actually capturing the Ordered list.
EDIT: To solve the repository problem, you can have a repository factory of sorts that returns the correct repository based on the type of T:
public static IMyTypeRepository GetRepository(Type t)
{
if(t == typeof(Type1))
{
return Type1Repository();
}
if(t == typeof(Type2))
{
return Type2Repository();
}
.......
}
Assuming of course that all your repositories implement the IMyRepository interface.
First of all, all your types must implement a common interface that define properties like Active, Value ...
Also, for what I can tell, there must be a repository interface for all repositories independently of the MyType so that you can use a generic method like this. The GetAll() method should be defined in the IRepository.
public interface IRepository<T> where T : IMyType
{
IList<T> GetAll();
}
public class RepositoryFactory
{
public static IRepository<T> createRepository<T>(ISessionBuilder sb) where T : IMyType
{
// create repository
}
}
public interface IMyType
{
bool Active { get; }
string Value { get; }
}
private static IList<T> GetList(RequestForm form) where T : IMyType
{
// get base list
IRepository<T> repository = RepositoryFactory.createRepository<T>(new HybridSessionBuilder());
IList<T> myTypes = repository.GetAll();
// create results list
IList<T> result = new List<T>();
// iterate for active + used list items
foreach (T myType in myTypes)
{
if (myType.Active || form.SolutionType.Contains(myType.Value))
{
result.Add(myType);
}
}
// return sorted results
return result.OrderBy(o => o.DisplayOrder).ToList();
}
Assuming that the repositories share a common interface, the issue with the repository should be easy to fix: add a static function such as
public static IRepository RepositoryForType(Type t)
{
if(t == typeof(SomeClass))
return new SomeClassRepository(new HybridSession());
else if ...
else throw new InvalidOperationException("No repository for type " + t.Name);
}
This should require you the least amount of changes to your existing code, but mind that in the future you'll have to add classes support for new repositories in this function as you add new repositories in your project (if you're using unit testing you'll easily figure out if you forgot about this helper anyway).