How do i implement IEnumerable<T>
?
Background
Lets say i have a class that i want to implement IEnumerable<T>
:
TStackoverflow<T> = class(TInterfacedObject, IEnumerable<T>)
public
{ IEnumerable<T> }
function GetEnumerator: IEnumerator<T>;
end;
var
IEnumerable<TMouse> mices = TStackoverflow<TMouse>.Create;
i would have an implementation:
TStackoverflow<T> = class(TInterfacedObject, IEnumerable<T>)
public
{ IEnumerable<T> }
function GetEnumerator: IEnumerator<T>;
end;
function TStackoverflow<T>.GetEnumerator: IEnumerator<T>;
begin
Result := {snip, not important here};
end;
Now, in order to be a good programmer, i will choose that my class will also support the IEnumerable
interface:
TStackoverflow<T> = class(TInterfacedObject, IEnumerable<T>, IEnumerable)
public
{ IEnumerable<T> }
function GetEnumerator: IEnumerator<T>;
{ IEnumerable }
function GetEnumerator: IEnumerator;
end;
function TStackoverflow<T>.GetEnumerator: IEnumerator<T>;
begin
Result := {snip, not important here};
end;
function TStackoverflow.GetEnumerator: IEnumerator;
begin
Result := {snip, not important here};
end;
Those of you who know where this is going, will know that implementing IEnumerable
is a red-herring; and had to be done either way.
Now comes the problem
That code doesn't compile, because:
function GetEnumerator: IEnumerator<T>;
function GetEnumerator: IEnumerator;
i have two methods with the same signature (not really the same signature, but same enough that Delphi can't distinguish between them):
E2254 Overloaded procedure 'GetEnumerator' must be marked with the 'overload' directive
Ok, fine, i'll mark them as overloads
:
function GetEnumerator: IEnumerator<T>; overload;
function GetEnumerator: IEnumerator; overload;
But that doesn't work:
E2252 Method 'GetEnumerator' with identical parameters already exists
Interface method resolution
Overloading was the wrong approach, we should be looking to method resolution clauses:
type
TStackoverflow<T> = class(TInterfacedObject, IEnumerable<T>, IEnumerable)
protected
function GetEnumeratorTyped: IEnumerator<T>;
function GetEnumeratorGeneric: IEnumerator;
public
function IEnumerable<T>.GetEnumerator = GetEnumeratorTyped;
function IEnumerable.GetEnumerator = GetEnumeratorGeneric;
end;
{ TStackoverflow }
function TStackoverflow<T>.GetEnumeratorGeneric: IEnumerator;
begin
end;
function TStackoverflow<T>.GetEnumeratorTyped: IEnumerator<T>;
begin
end;
Except this doesn't compile either, for reasons that escape me:
E2291 Missing implementation of interface method IEnumerable.GetEnumerator
So lets forget IEnumerable
Pretend i don't care if my class doesn't support IEnumerable
, lets remove it as a supported interface. It doesn't actually change anything, as IEnumerable<T>
descends from IEnumerble
:
IEnumerable<T> = interface(IEnumerable)
function GetEnumerator: IEnumerator<T>;
end;
so the method must exist, and the code that removes IEnumerable
:
type
TStackoverflow<T> = class(TInterfacedObject, IEnumerable<T>)
protected
function GetEnumeratorTyped: IEnumerator<T>;
public
function IEnumerable<T>.GetEnumerator = GetEnumeratorTyped;
end;
{ TStackoverflow }
function TStackoverflow<T>.GetEnumeratorTyped: IEnumerator<T>;
begin
end;
doesn't compile for the same reason:
E2291 Missing implementation of interface method IEnumerable.GetEnumerator
Alright then, forget generics
So lets stop, collaborate and listen. IEnumerable is back as an old new invention:
type
TStackoverflow = class(TInterfacedObject, IEnumerable)
public
function GetEnumerator: IEnumerator;
end;
{ TStackoverflow }
function TStackoverflow.GetEnumerator: IEnumerator;
begin
end;
Excellent, that works. I can have my class support IEnumerable
. Now i want to support IEnumerable<T>
.
Which leads me to my question:
Update: Forgot to attach complete non-functional code:
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils;
type
TStackoverflow<T> = class(TInterfacedObject, IEnumerable<T>, IEnumerable)
protected
function GetEnumeratorTyped: IEnumerator<T>;
function GetEnumeratorGeneric: IEnumerator;
public
function IEnumerable<T>.GetEnumerator = GetEnumeratorTyped;
function IEnumerable.GetEnumerator = GetEnumeratorGeneric;
end;
{ TStackoverflow<T> }
function TStackoverflow<T>.GetEnumeratorGeneric: IEnumerator;
begin
end;
function TStackoverflow<T>.GetEnumeratorTyped: IEnumerator<T>;
begin
end;
begin
try
{ TODO -oUser -cConsole Main : Insert code here }
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.