Override IEnumerable<T> Where - c#

I've written a class that implements IEnumerable :
public class MyEnumerable : IEnumerable<MyClass>
{
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
public IEnumerator<MyClass> GetEnumerator()
{
//Enumerate
}
}
I'd like to "override" the Where method. What I want to do is :
MyEnumerable myEnumerable = new MyEnumerable();
MyEnumerable myEnumerable2 = myEnumerable.Where(/*some predicate*/);
This is not possible for the moment because myEnumerable.Where() returns an IEnumerable.
What I want is that myEnumerable.Where() returns a MyEnumerable.
Is that possible to do this ?
Thank you

Sure - just add a Where method to MyEnumerable. The Linq Where method is an extension method, so it's not technically an override. you're "hiding" the linq method.
public class MyEnumerable : IEnumerable<MyClass>
{
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
public IEnumerator<MyClass> GetEnumerator()
{
//Enumerate
}
public MyEnumerable Where()
{
// implement `Where`
}
}
There are some caveats, though:
Your Where method will only be called if the declared type is MyEnumerable - it will not be called on variables of type IEnumerable<MyClass> (or any collection that implements it, like List<MyClass>
There are several overloads of Where that will need to be implemented as well if you want to maintain consistently with Linq.

Update
From your comment your enumerator is a lazy file enumerator and you want to be able to select items from it based on a predicate and still have the laziness.
You could create another class inheriting that class or an interface to help with this.
Here is an example
public class FileItem
{
//Some properties
}
public interface IFileEnumerator : IEnumerable<FileItem>
{
IFileEnumerator Where(Func<FileItem, bool> predicate);
}
public class FileEnumerator : IFileEnumerator
{
private readonly string fileName;
public FileEnumerator(string fileName)
{
this.fileName = fileName;
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
public IEnumerator<FileItem> GetEnumerator()
{
var items = new List<FileItem>();
//Read from file and add lines to items
return items.GetEnumerator();
}
public IFileEnumerator Where(Func<FileItem, bool> predicate)
{
return new MemoryEnumerator(ToEnumerable(GetEnumerator()).Where(predicate));
}
private static IEnumerable<T> ToEnumerable<T>(IEnumerator<T> enumerator)
{
while (enumerator.MoveNext())
{
yield return enumerator.Current;
}
}
}
public class MemoryEnumerator : IFileEnumerator
{
private readonly IEnumerable<FileItem> items;
public MemoryEnumerator(IEnumerable<FileItem> items)
{
this.items = items;
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
public IEnumerator<FileItem> GetEnumerator()
{
return items.GetEnumerator();
}
public IFileEnumerator Where(Func<FileItem, bool> predicate)
{
return new MemoryEnumerator(items.Where(predicate));
}
}

Related

Using reflection to find an enumerator's method

Background:
I am modifying existing code using the Harmony Library. The existing C# code follows this structure:
public class ToModify
{
public override void Update()
{
foreach (StatusItemGroup.Entry entry in collection)
{
// I am trying to alter an operation at the end of this loop.
}
}
}
public class StatusItemGroup
{
public IEnumerator<Entry> GetEnumerator()
{
return items.GetEnumerator();
}
private List<Entry> items = new List<Entry>();
public struct Entry { }
}
Due to the situation, I must modify the IL code that is being generated, to do so I must obtain the MethodInfo of my target operand. This is the target:
IL_12B6: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
Question:
How do I obtain the MethodInfo for the MoveNext method of an enumerator?
What I've tried:
Everything I can think of has yielded null results. This is my most basic attempt:
MethodInfo targetMethod = typeof(IEnumerator<StatusItemGroup.Entry>).GetMethod("MoveNext");
I don't understand why this doesn't work, and I don't know what I need to do to correctly obtain the MethodInfo.
MoveNext is not defined on IEnumerator<T>, but on the non-generic IEnumerator which is inherited by IEnumerator<T>.
Interface inheritance is a little weird in combination with reflection, so you need to obtain the method info directly from the base interface where it's defined:
MethodInfo targetMethod = typeof(System.Collections.IEnumerator).GetMethod("MoveNext");
Using the free LinqPad, I create this with Harmony 2.0 RC2. As you can see did I use a pass-through postfix to change the enumerator and wrap it. There are other ways and I suspect that you actually have an IEnumeration somewhere instead. That would be way easier to patch by using the pass-through postfix directly on the original method that returns the IEnumeration. No need to wrap the enumerator in that case.
But I don't know your full use case, so for now, this is the working example:
void Main()
{
var harmony = new Harmony("test");
harmony.PatchAll();
var group = new StatusItemGroup();
var items = new List<StatusItemGroup.Entry>() { StatusItemGroup.Entry.Make("A"), StatusItemGroup.Entry.Make("B") };
Traverse.Create(group).Field("items").SetValue(items);
var enumerator = group.GetEnumerator();
while(enumerator.MoveNext())
Console.WriteLine(enumerator.Current.id);
}
[HarmonyPatch]
class Patch
{
public class ProxyEnumerator<T> : IEnumerable<T>
{
public IEnumerator<T> enumerator;
public Func<T, T> transformer;
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
public IEnumerator<T> GetEnumerator()
{
while(enumerator.MoveNext())
yield return transformer(enumerator.Current);
}
}
[HarmonyPatch(typeof(StatusItemGroup), "GetEnumerator")]
static IEnumerator<StatusItemGroup.Entry> Postfix(IEnumerator<StatusItemGroup.Entry> enumerator)
{
StatusItemGroup.Entry Transform(StatusItemGroup.Entry entry)
{
entry.id += "+";
return entry;
}
var myEnumerator = new ProxyEnumerator<StatusItemGroup.Entry>()
{
enumerator = enumerator,
transformer = Transform
};
return myEnumerator.GetEnumerator();
}
}
public class StatusItemGroup
{
public IEnumerator<Entry> GetEnumerator()
{
return items.GetEnumerator();
}
private List<Entry> items = new List<Entry>();
public struct Entry
{
public string id;
public static Entry Make(string id) { return new Entry() { id = id }; }
}
}

Generic extension method to convert from one collection to another

I'm working in a code base which has a lot of first class collections.
In order to ease using these collections with LINQ, there is an extension method per collection that looks like:
public static class CustomCollectionExtensions
{
public static CustomCollection ToCustomCollection(this IEnumerable<CustomItem> enumerable)
{
return new CustomCollection(enumerable);
}
}
With the accompanying constructors:
public class CustomCollection : List<CustomItem>
{
public CustomCollection(IEnumerable<CustomItem> enumerable) : base(enumerable) { }
}
This winds up being a bunch of boilerplate so I attempted to write a generic IEnumerable<U>.To<T>() so that we wouldn't have to keep generating these specific ToXCollection() methods.
I got as far as:
public static class GenericCollectionExtensions
{
public static T To<T, U>(this IEnumerable<U> enumerable) where T : ICollection<U>, new()
{
T collection = new T();
foreach (U u in enumerable)
{
collection.Add(u);
}
return collection;
}
}
Which has to be called like customCollectionInstance.OrderBy(i => i.Property).To<CustomCollection, CustomItem>()
Is there a way to avoid having to specify the CustomItem type so we can instead use customCollectionInstance.OrderBy(i => i.Property).To<CustomCollection>() or is this not something that can be done generically?
Something close to what you want:
public static class GenericCollectionExtensions
{
public sealed class CollectionConverter<TItem>
{
private readonly IEnumerable<TItem> _source;
public CollectionConverter(IEnumerable<TItem> source)
{
_source = source;
}
public TCollection To<TCollection>()
where TCollection : ICollection<TItem>, new()
{
var collection = new TCollection();
foreach(var item in _source)
{
collection.Add(item);
}
return collection;
}
}
public static CollectionConverter<T> Convert<T>(this IEnumerable<T> sequence)
{
return new CollectionConverter<T>(sequence);
}
}
Usage:
customCollectionInstance.OrderBy(i => i.Property).Convert().To<CustomCollection>();

How can I create a typed IEnumerable in C#?

I can do this:
public class EnumerableTest : System.Collections.IEnumerable
{
System.Collections.IEnumerable data;
public EnumerableTest(System.Collections.IEnumerable d)
{
data = d;
}
public System.Collections.IEnumerator GetEnumerator()
{
foreach (object s in data)
{
yield return s;
}
}
}
But I can't do this?:
public class EnumerableTestString : System.Collections.Generic.IEnumerable<string>
{
System.Collections.Generic.IEnumerable<string> data;
public EnumerableTestString(System.Collections.Generic.IEnumerable<string> d)
{
data = d;
}
public System.Collections.Generic.IEnumerator<string> GetEnumerator()
{
foreach (string s in data)
{
yield return s;
}
}
}
The error I get basically says I am missing the method
public System.Collections.IEnumerator GetEnumerator();
When I change the return type of GetEnumerator() to that, then it tells me I am missing
public System.Collections.Generic.IEnumerator<string> GetEnumerator();
If I try to include both, it tells me I have a duplicate method name.
How can I solve this?
How can I solve this?
You need to use explicit interface implementation to implement at least one of the GetEnumerator methods, usually the non-generic one.
The code is simply with using directives :)
using System.Collections;
using System.Collections.Generic;
public class EnumerableTestString : IEnumerable<string>
{
private IEnumerable<string> data;
public EnumerableTestString(IEnumerable<string> d)
{
data = d;
}
public IEnumerator<string> GetEnumerator()
{
foreach (string s in data)
{
yield return s;
}
}
// Explicit interface implementation for non-generic IEnumerable
public IEnumerator IEnumerable.GetEnumerator()
{
// Delegate to the generic version
return GetEnumerator();
}
}
Create both - e.g. an Explicit implementation that will call the Implicit implementation.
Example:
public class EnumerableTestString : System.Collections.Generic.IEnumerable<string>
{
System.Collections.Generic.IEnumerable<string> data;
public EnumerableTestString(System.Collections.Generic.IEnumerable<string> d)
{
data = d;
}
public System.Collections.Generic.IEnumerator<string> GetEnumerator()
{
foreach (string s in data)
{
yield return s;
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Implement System.Collections.Generic.IEnumerable<T> instead.
When you do so using VS's smart tag, VS automatically creates two methods. One for the generic implementation and one for the non-generic one (the one you have already) because IEnumerable<T> requires you to implement IEnumerable as well.
public class StringData : IEnumerable<string>
{
...
#region IEnumerable<string> Members
public IEnumerator<string> GetEnumerator()
{
foreach (string s in data) {
yield return s;
}
}
#endregion
#region IEnumerable Members
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator(); // Calls generic GetEnumerator
}
#endregion
}
Note that the non generic method is implemented explicitly and can therefore only be accessed through the interface (IEnumerable x = ...; x.GetEnumerator()). Its purpose is to increase the compatibility and is a remnant of pre-generic c# versions (1.0, 1.1).

How to serialize in a XML a custom IEnumerable?

I've created a class which derives from IEnumerable<T>. T is a OQTemplate, and this one implements IXmlSerializable correctly. But I don't know how to implement the following class.
public class OQTemplateCollection : IEnumerable<OQTemplate>, IEnumerable
{
private readonly List<OQTemplate> entries;
public OQTemplateCollection()
{
this.entries = new List<OQTemplate>();
}
public OQTemplateCollection(IEnumerable<OQTemplate> source)
{
this.entries = new List<OQTemplate>(source);
}
public void Add(OQTemplate qt)
{
entries.Add(qt);
}
public IEnumerator<OQTemplate> GetEnumerator()
{
return entries.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public OQTemplate this[int index]
{
get { return entries[index]; }
}
}
I'd like just to have a XML like this:
<OQTemplateCollection>
<OQTemplate ... />
<OQTemplate ... />
</OQTemplateCollection>

C#: List add object initializer

Lets say I have this class:
class MyList<T>
{
}
What must I do to that class, to make the following possible:
var list = new MyList<int> {1, 2, 3, 4};
Have an Add method and implement IEnumerable.
class MyList<T> : IEnumerable
{
public void Add(T t)
{
}
public IEnumerator GetEnumerator()
{
//...
}
}
public void T()
{
MyList<int> a = new MyList<int>{1,2,3};
}
Implementing ICollection on MyList will let the initalizer syntax work
class MyList<T> : ICollection<T>
{
}
Although the bare minimum would be:
public class myList<T> : IEnumerable<T>
{
public void Add(T val)
{
}
public IEnumerator<T> GetEnumerator()
{
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
}
}
ICollection<T> is also good.

Categories