Implementing C# IEnumerable<T> for a LinkedList class - c#

I'm trying to write a custom LinkedList class in C# using monoDevelop on Linux, just for the sake of testing and learning. The following code never compiles, and I have no idea why!! It doesn't even tell me what's wrong. All what it says is: Error: The compiler appears to have crashed. Check the build output pad for details. When I go to check the output pad, it's not helpful either:
Unhandled Exception: System.ArgumentException: The specified field must be declared on a generic type definition.
Parameter name: field
What can I do?
using System;
using System.Text;
using System.Collections.Generic;
namespace LinkedList
{
public class myLinkedList<T> : IEnumerable<T>
{
//List Node class
//===============
private class ListNode<T>
{
public T data;
public ListNode<T> next;
public ListNode(T d)
{
this.data = d;
this.next = null;
}
public ListNode(T d, ListNode<T> n)
{
this.data = d;
this.next = n;
}
}
//priavte fields
//===============
private ListNode<T> front;
private int size;
//Constructor
//===========
public myLinkedList ()
{
front = null;
size = 0;
}
//public methods
//===============
public bool isEmpty()
{
return (size == 0);
}
public bool addFront(T element)
{
front = new ListNode<T>(element, front);
size++;
return true;
}
public bool addBack(T element)
{
ListNode<T> current = front;
while (current.next != null)
{
current = current.next;
}
current.next = new ListNode<T>(element);
size++;
return true;
}
public override string ToString()
{
ListNode<T> current = front;
if(current == null)
{
return "**** Empty ****";
}
else
{
StringBuilder sb = new StringBuilder();
while (current.next != null)
{
sb.Append(current.data + ", ");
current = current.next;
}
sb.Append(current.data);
return sb.ToString();
}
}
// These make myLinkedList<T> implement IEnumerable<T> allowing
// a LinkedList to be used in a foreach statement.
public IEnumerator<T> GetEnumerator()
{
return new myLinkedListIterator<T>(front);
}
private class myLinkedListIterator<T> : IEnumerator<T>
{
private ListNode<T> current;
public virtual T Current
{
get
{
return current.data;
}
}
private ListNode<T> front;
public myLinkedListIterator(ListNode<T> f)
{
front = f;
current = front;
}
public bool MoveNext()
{
if(current.next != null)
{
current = current.next;
return true;
}
else
{
return false;
}
}
public void Reset()
{
current = front;
}
public void Dispose()
{
throw new Exception("Unsupported Operation");
}
}
}
}

You need to add the non-generic APIs; so add to the iterator:
object System.Collections.IEnumerator.Current { get { return Current; } }
and to the enumerable:
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
HOWEVER! If you are implementing this by hand, you are missing a trick. An "iterator block" would be much easier.
The following is a complete implementation; you don't need to write an enumerator class at all (you can remove myLinkedListIterator<T> completely):
public IEnumerator<T> GetEnumerator()
{
var node = front;
while(node != null)
{
yield return node.data;
node = node.next;
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}

When i tried the code that you have pasted i get 2 errors when trying to build.
myLinkedList' does not implement interface member
'System.Collections.IEnumerable.GetEnumerator()'.
'.myLinkedList.GetEnumerator()' cannot implement
'System.Collections.IEnumerable.GetEnumerator()' because it does not
have the matching return type of 'System.Collections.IEnumerator'.
Solution is to implement the following in the first class.
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
And the second error is :
myLinkedList.myLinkedListIterator' does not implement interface
member 'System.Collections.IEnumerator.Current'.
'JonasApplication.myLinkedList.myLinkedListIterator.Current'
cannot implement 'System.Collections.IEnumerator.Current' because it
does not have the matching return type of 'object'.
Solution to the second could be something as following to implement in the second class.
object IEnumerator.Current
{
get { return Current; }
}

Related

Cannot yield even though the return type is IEnumerable<U>

Consider the following trivial example:
class Filter<T, U>
where T : IEnumerable<U>
where U : IEquatable<U>
{
private readonly U id;
public Filter(U id) => this.id = id;
public T Eval_A(T items)
{
foreach (var item in items)
if (item.Equals(id))
yield return item;
}
public IEnumerable<U> Eval_B(IEnumerable<U> items)
{
foreach (var item in items)
if (item.Equals(id))
yield return item;
}
}
Even though T is of type IEnumerable<U>, an error still occurs for T Eval_A(T items) as follows.
The body of 'accessor' cannot be an iterator block because 'type' is not an iterator interface type
MSDN said:
This error occurs if an iterator accessor is used but the return type is not one of the iterator interface types: IEnumerable, IEnumerable<T>, IEnumerator, IEnumerator<T>. To avoid this error, use one of the iterator interface types as a return type.
I think the return type does conforms to the requirement.
What am I missing here?
The return type of the method has to be exactly one of IEnumerable, IEnumerable<T>, IEnumerator or IEnumerator<T>, and not T, which is some type that implements IEnumerable<U>.
This is because the way that iterator methods work, is that the compiler generates a type implementing one of the above interfaces, with the MoveNext and Current correctly implemented so that it matches the behaviour of your method, and then it rewrites your method to return an instance of that type instead.
For example, for:
public IEnumerable<int> GetSingleDigitNumbersLoop()
{
int index = 0;
while (index < 10)
yield return index++;
}
The following is generated (seen using SharpLab.io):
[IteratorStateMachine(typeof(<GetSingleDigitNumbersLoop>d__0))]
public IEnumerable<int> GetSingleDigitNumbersLoop()
{
return new <GetSingleDigitNumbersLoop>d__0(-2);
}
[CompilerGenerated]
private sealed class <GetSingleDigitNumbersLoop>d__0 : IEnumerable<int>, IEnumerable, IEnumerator<int>, IDisposable, IEnumerator
{
private int <>1__state;
private int <>2__current;
private int <>l__initialThreadId;
private int <index>5__2;
int IEnumerator<int>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <GetSingleDigitNumbersLoop>d__0(int <>1__state)
{
this.<>1__state = <>1__state;
<>l__initialThreadId = Environment.CurrentManagedThreadId;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
}
private bool MoveNext()
{
int num = <>1__state;
if (num != 0)
{
if (num != 1)
{
return false;
}
<>1__state = -1;
}
else
{
<>1__state = -1;
<index>5__2 = 0;
}
if (<index>5__2 < 10)
{
<>2__current = <index>5__2++;
<>1__state = 1;
return true;
}
return false;
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
[DebuggerHidden]
IEnumerator<int> IEnumerable<int>.GetEnumerator()
{
if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
{
<>1__state = 0;
return this;
}
return new <GetSingleDigitNumbersLoop>d__0(0);
}
[DebuggerHidden]
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable<int>)this).GetEnumerator();
}
}
<GetSingleDigitNumbersLoop>d__0 is the type that implements IEnumerable<int> that GetSingleDigitNumbersLoop is rewritten to return instead.
Now, if GetSingleDigitNumbersLoop were declared to return some other type, like a type parameter T for example, the following wouldn't work:
public T GetSingleDigitNumbersLoop()
{
return new <GetSingleDigitNumbersLoop>d__0(-2);
}
Because <GetSingleDigitNumbersLoop>d__0 is not necessarily a T. In fact it almost never would be, because it is a compiler generated type!
See also: yield statement implementation

How to make my InfiniteLoopingList class implement IEnumerable?

I am making a prototype application and for that I designed a class that behaves like an infinite looping list. That is, if my internal list contains 100 values, when I ask for the 101st value, I get the first, the 102nd yields the second, and so on, repeating.
So I would like to write the following code:
var slice = loopingListInstance.Skip(123).Take(5);
And for that I need to implement IEnumerable suitable, as I understand.
Here is my current code:
public class InfiniteLoopingList : IEnumerable<double>
{
double[] _values = File.ReadLines(#"c:\file.txt")
.Select(s => double.Parse(s, CultureInfo.InvariantCulture))
.ToArray();
int _size;
public InfiniteLoopingList()
{
_size = _values.Length;
}
public double this[int i]
{
get { return _values[i % _size]; }
set { _values[i % _size] = value; }
}
public IEnumerator<double> GetEnumerator()
{
return this.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
// ???? now what ?? :(
}
}
Since you implemented the indexer property, you could do it via the simplest way as follows:
public IEnumerator<double> GetEnumerator()
{
int i = 0;
while (true)
yield return this[i++];
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
EDIT
Please notice, that this is not really infinite loop. This approach will only work until i = int.MaxValue. Thanks to #oleksii.
You don't need a class for this...
An extension method will do the trick:
public static class InfEx
{
public static IEnumerable<T> LoopForever<T>(this IEnumerable<T> src)
{
var data = new List<T>();
foreach(var item in src)
{
data.Add(item);
yield return item;
}
for(;;)
{
foreach(var item in data)
{
yield return item;
}
}
}
}
Now you can take a sequence and make it a looping, infinite sequence:
IEnumerable<Foo> mySeq = ...;
IEnumerable<Foo> infMySeq = mySeq.LoopForver();
IEnumerable<Foo> aSelectionOfInfMySeq = infMySeq.Skip(101).Take(5);
You can implement the IEnumerator interface:
class InifniteEnumerator<T> : IEnumerator<T> {
private int index = -1;
private IList<T> innerList;
private int repeatPos;
public InifniteEnumerator(IList<T> innerList, int repeatPos) {
this.innerList = innerList;
this.repeatPos = repeatPos;
}
public T Current {
get {
if (index == -1) {
throw new InvalidOperationException();
}
return this.innerList[index];
}
}
object IEnumerator.Current {
get {
return this.Current;
}
}
public void Dispose() {
}
public bool MoveNext() {
this.index++;
if (this.index == repeatPos) {
this.index = 0;
}
return true;
}
public void Reset() {
this.index = -1;
}
}
and then return an instance of it in the GetEnumerator methods:
IEnumerator IEnumerable.GetEnumerator() {
return this.GetEnumerator();
}
public IEnumerator<T> IEnumerable<T>.GetEnumerator() {
return new InifniteEnumerator(this, 100);
}

Implementing IEnumerable to my object [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Implementing C# IEnumerable<T> for a LinkedList class
After searching the web for some hours now I still can't understand how IEnumerable/IEnumerator works and how to implement it.
I've constructed a simple LinkedList from scratch but now I want to implement IEnumerable for it so I can foreach it. How do I do that?
class Program
{
LL myList = new LL();
static void Main()
{
var gogo = new Program();
}
public Program()
{
myList.Add("test");
myList.Add("test1");
foreach (var item in myList) //This doesn't work because I havn't implemented Ienumerable
Console.WriteLine(item);
Console.Read();
}
}
class LL
{
private LLNode first;
public void Add(string s)
{
if (this.first == null)
this.first = new LLNode() { Value = s };
else
{
var node = this.first;
while (node.Next != null)
node = node.Next;
node.Next = new LLNode() { Value = s };
}
}
class LLNode
{
public string Value { get; set; }
public LLNode Next { get; set; }
}
It's really not that hard. To implement IEnumerable you just need to implement the GetEnumerator method.
To do that you need to create another class that implements IEnumerator. Implementing IEnumerator is pretty easy. Generally you will pass a reference to your collection when you create the enumerator (in GetEnumerator) and the enumerator will keep track of which item is the current item. Then it will provide MoveNext which just changes the Current to the next item (and returns false if it's at the end of the list) and Reset which just sets the Current back to before the first node.
So in very broad, untested code terms, you need something like:
public class MyLinkedListEnumerator : IEnumerator
{
private LL myList;
private LLNode current;
public object Current
{
get { return current; }
}
public MyLinkedListEnumerator(LL myList)
{
this.myList = myList;
}
public bool MoveNext()
{
if (current == null) {
current = myList.first;
}
else {
current = current.Next;
}
return current != null;
}
public void Reset()
{
current = null;
}
}
What you need to do is:
(1) Make your class implement IEnumerable<T> where T is the type of the enumerated items. (In your case, it looks like it would be LLNode).
(2) Write a public IEnumerator<T> GetEnumerator. Implement it using the "yield" keyword.
(3) Add a IEnumerator IEnumerable.GetEnumerator() method and just return GetEnumerator().
The following code should make this clear. Where I have <int>, you should put <LLNode>, assuming that is the correct type.
using System;
using System.Collections;
using System.Collections.Generic;
namespace Demo
{
internal class Program
{
private static void Main()
{
var test = new MyDemo();
foreach (int item in test)
{
Console.WriteLine(item);
}
}
}
public class MyDemo: IEnumerable<int>
{
public IEnumerator<int> GetEnumerator()
{
// Your implementation of this method will iterate over your nodes
// and use "yield return" to return each one in turn.
for (int i = 10; i <= 20; ++i)
{
yield return i;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
I would have modified your code to do it properly, but the code you posted won't compile.
[EDIT]
Now you've updated your code, I can see that you want to enumerate the values. Here's the completed code:
using System;
using System.Collections;
using System.Collections.Generic;
namespace Demo
{
internal class Program
{
private LL myList = new LL();
private static void Main()
{
var gogo = new Program();
}
public Program()
{
myList.Add("test");
myList.Add("test1");
foreach (var item in myList) // This now works.
Console.WriteLine(item);
Console.Read();
}
}
internal class LL: IEnumerable<string>
{
private LLNode first;
public void Add(string s)
{
if (this.first == null)
this.first = new LLNode
{
Value = s
};
else
{
var node = this.first;
while (node.Next != null)
node = node.Next;
node.Next = new LLNode
{
Value = s
};
}
}
public IEnumerator<string> GetEnumerator()
{
for (var node = first; node != null; node = node.Next)
{
yield return node.Value;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
private class LLNode
{
public string Value { get; set; }
public LLNode Next { get; set; }
}
}
}

call graph IEnumerator

I have to implement a call graph for expressions like Id = Id(Param); and that wasn't a problem.
Now I have to implement an enumerator which lists one at a time all topological orderings among the calls that satisfy the order of dependencies.
And here's the trouble.
This is a simple node for the call graph:
class CallGraphNode
{
private string name;
public List<CallGraphNode> dependents = new List<CallGraphNode>();
public int dependencies;
private bool executed = false;
public bool Executable { get { return dependencies == 0; } }
public bool Executed { get { return executed; } set { executed = value; } }
public CallGraphNode(string name)
{
this.name = name;
dependencies = 0;
}
public override string ToString()
{
return name;
}
public void AddDependent(CallGraphNode n)
{
dependents.Add(n);
}
}
And this is the call graph class itself:
class CallGraph : IEnumerable<List<CallGraphNode>>
{
public List<CallGraphNode> nodes = new List<CallGraphNode>();
public void AddNode(CallGraphNode n)
{
nodes.Add(n);
}
public static void Show(IEnumerable<CallGraphNode> n)
{
foreach (CallGraphNode node in n)
{
Console.Write("{0} ", node);
}
Console.WriteLine();
}
static IEnumerable<List<CallGraphNode>> EnumerateFunctions(List<CallGraphNode> executable, List<CallGraphNode> res)
{
if (executable.Count == 0)
yield return res;
else foreach (CallGraphNode n in executable)
{
if (!n.Executed)
res.Add(n);
List<CallGraphNode> next_executable = new List<CallGraphNode>(executable);
executable.Remove(n);
foreach (CallGraphNode m in n.dependents)
if (--m.dependencies == 0)
next_executable.Add(m);
foreach (List<CallGraphNode> others in EnumerateFunctions(next_executable, res))
yield return others;
foreach (CallGraphNode m in n.dependents)
m.dependencies++;
if (!n.Executed)
res.Remove(n);
}
}
IEnumerator<List<CallGraphNode>> IEnumerable<List<CallGraphNode>>.GetEnumerator()
{
List<CallGraphNode> executable = new List<CallGraphNode>();
foreach (CallGraphNode n in nodes)
if (n.Executable || n.Executed)
executable.Add(n);
List<CallGraphNode> output = new List<CallGraphNode>();
foreach (List<CallGraphNode> list in EnumerateFunctions(executable, output))
yield return list;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{ throw new NotImplementedException(); }
}
Now, the problem is it just won't work. When I try to create an IEnumerator and assign it the GetEnumerator() return value, I get a casting error and that's honestly what I expected when trying to do so:
IEnumerator<List<CallGraphNode>> lt = cg.GetEnumerator();
Then I've tried:
System.Collections.Generic.List<CallGraphNode>.Enumerator en = cg.nodes.GetEnumerator();
This works, but the method EnumerateFunctions is never called and the enumerator just contains the original list of graph nodes.
Any ideas?
The problem is that you're implementing both IEnumerable<T> and IEnumerable using explicit interface implementation.
You probably want to change this declaration:
IEnumerator<List<CallGraphNode>> IEnumerable<List<CallGraphNode>>.GetEnumerator()
to be a "normal" interface implementation:
public IEnumerator<List<CallGraphNode>> GetEnumerator()
Alternatively, you could stick with explicit interface implementation, but use:
IEnumerable<List<CallGraphNode>> sequence = cg;
IEnumerator<List<CallGraphNode>> lt = sequence.GetEnumerator();

Is it possible to have C++-like generics in C#?

Perhaps this question was already asked million times but I couldn't find similar topic. Is it possible to write a generic class with multiple 'where'-s that will be checked in compile time? Here is what I have today
public class MsBitsEnumWrapper<TC, TE> : IEnumerable<TC>
{
internal class Helper : IEnumerator<TC>
{
private readonly TC[] _data;
private int _pos = -1;
private readonly IEnumBackgroundCopyJobs _jobs;
private readonly IEnumBackgroundCopyFiles _files;
// I miss C++ templates that allows me to implements this method in completelly generic fashion...
public Helper(TE source)
{
_jobs = source as IEnumBackgroundCopyJobs;
_files = source as IEnumBackgroundCopyFiles;
uint count = 0;
if (null != _jobs)
{
_jobs.GetCount(out count);
_jobs.Reset();
}
else
if (null != _files)
{
_files.GetCount(out count);
_files.Reset();
}
_data = new TC[count];
for (uint i = 0; i < count; ++i)
{
uint fetched = 0;
if (null != _jobs)
{
IBackgroundCopyJob job;
_jobs.Next(1, out job, ref fetched);
_data[i] = (TC)job;
}
else
if (null != _files)
{
IBackgroundCopyFile file;
_files.Next(1, out file, ref fetched);
_data[i] = (TC)file;
}
}
}
#region Implementation of IDisposable
public void Dispose() { }
#endregion
#region Implementation of IEnumerator
public bool MoveNext()
{
if (_pos < (_data.Length - 1))
{
_pos++;
return true;
}
return false;
}
public void Reset()
{
_pos = -1;
}
public TC Current
{
get { return _data[_pos]; }
}
object IEnumerator.Current
{
get { return Current; }
}
#endregion
}
private readonly Helper _enumerator;
public MsBitsEnumWrapper(TE source) { _enumerator = new Helper(source); }
#region Implementation of IEnumerable
public IEnumerator<TC> GetEnumerator() { return _enumerator; }
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
#endregion
}
Obviously I don't like it because I have to have switch in run-time that detect the type of generic argument. Is it possible to have something like this ?
public class MsBitsEnumWrapper<TC, TE> : IEnumerable<TC>
where TE : IEnumBackgroundCopyJobs, IEnumBackgroundCopyFiles
where TC : IBackgroundCopyJob, IBackgroundCopyFile
{
internal class Helper : IEnumerator<TC>
{
private readonly TC[] _data;
private int _pos = -1;
private readonly TE _iface;
// I miss C++ templates that allows me to implements this method in completelly generic fashion...
public Helper(TE source)
{
_iface = source;
uint count;
_iface.GetCount(out count);
_iface.Reset();
_data = new TC[count];
for (uint i = 0; i < count; ++i)
{
uint fetched = 0;
TC job;
_iface.Next(1, out job, ref fetched);
_data[i] = job;
}
}
#region Implementation of IDisposable
public void Dispose() { }
#endregion
#region Implementation of IEnumerator
public bool MoveNext()
{
if (_pos < (_data.Length - 1))
{
_pos++;
return true;
}
return false;
}
public void Reset()
{
_pos = -1;
}
public TC Current
{
get { return _data[_pos]; }
}
object IEnumerator.Current
{
get { return Current; }
}
#endregion
}
private readonly Helper _enumerator;
public MsBitsEnumWrapper(TE source) { _enumerator = new Helper(source); }
#region Implementation of IEnumerable
public IEnumerator<TC> GetEnumerator() { return _enumerator; }
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
#endregion
}
I realize that it won't work if generic is defined with TE=IEnumBackgroundCopyJobs and TC=IBackgroundCopyFile, but since I'm the one who defines TE and TC and function prototypes of given interfaces are the same it would be nice to have it work this way.
Or may be there is another way to simplify current code ?
Thanks!
As JaredPar indicated, you can't do this in C#. The choices are to use delegates, or go old school with using an abstract base class.
My implementation below take advantage of 'yield return' to cut down on the implementation of IEnumerable.
#if USE_DELEGATES
public class MsBitsEnum<T> : IEnumerable<T>
{
Action _reset;
Func<T> _next;
Func<int> _count;
public MsBitsEnum(Action reset, Func<T> next, Func<int> count)
{
_reset = reset;
_next = next;
_count = count;
}
public IEnumerator<T> GetEnumerator()
{
_reset();
int count = _count();
for (int i = 0; i < count; ++i)
yield return _next();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public class MsBitsJobs : MsBitsEnum<IBackgroundCopyJob>
{
public MsBitsJobs(IEnumBackgroundCopyJobs jobs)
: base(() => jobs.Reset(),
() =>
{
IBackgroundCopyJob job = null;
uint fetched = 0;
jobs.Next(1, out job, out fetched);
return fetched == 1 ? job : null;
},
() =>
{
uint count;
jobs.GetCount(out count);
return (int) count;
})
{
}
}
public class MsBitsFiles : MsBitsEnum<IBackgroundCopyFile>
{
public MsBitsFiles(IEnumBackgroundCopyFiles files)
: base(() => files.Reset(),
() =>
{
IBackgroundCopyFile file = null;
uint fetched = 0;
files.Next(1, out file, out fetched);
return fetched == 1 ? file : null;
},
() =>
{
uint count;
files.GetCount(out count);
return (int)count;
})
{
}
}
#else // !USE_DELEGATES
public abstract class MsBitsEnum<T> : IEnumerable<T>
{
protected abstract void Reset();
protected abstract bool Next(out T item);
public IEnumerator<T> GetEnumerator()
{
T item;
Reset();
while (Next(out item))
yield return item;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public class MsBitsJobs : MsBitsEnum<IBackgroundCopyJob>
{
IEnumBackgroundCopyJobs _jobs;
protected override void Reset()
{
_jobs.Reset();
}
protected override bool Next(out IBackgroundCopyJob job)
{
uint fetched;
_jobs.Next(1, out job, out fetched);
return fetched == 1;
}
public MsBitsJobs(IEnumBackgroundCopyJobs jobs)
{
_jobs = jobs;
}
}
public class MsBitsFiles : MsBitsEnum<IBackgroundCopyFile>
{
IEnumBackgroundCopyFiles _files;
protected override void Reset()
{
_files.Reset();
}
protected override bool Next(out IBackgroundCopyFile file)
{
uint fetched;
_files.Next(1, out file, out fetched);
return fetched == 1;
}
public MsBitsFiles(IEnumBackgroundCopyFiles files)
{
_files = files;
}
}
#endif // !USE_DELEGATES
It sounds like what you're asking is if C# supports structural typing in generics in the same way that C++ does for templates. The answer is No.
C++ templates aren't fully evaluated for correctness until the member functions are used with a given generic instantiation. C# generics on the other hand are fully evaluated on their own when they are compiled. It leaves no room for structural / match by name typing.
There are a couple of approaches you could take here. The more laborous approach is to create another interface for the GetCount and Reset functions. Then create wrapper types for the two interfaces to plug into these methods. This is a bit tedious though after a while.
My personal preference is to solve this problem with delegates.
public Helper(TE source, Func<TE,count> getCount, Action<TE> reset)
{
_iface = source;
uint count = getCount(_iface);
reset(_iface);
...
}

Categories