Как реализовать IEnumerable<T>?
Фон
Допустим, у меня есть класс, который я хочу реализовать IEnumerable<T>:
TStackoverflow<T> = class(TInterfacedObject, IEnumerable<T>)
public
{ IEnumerable<T> }
function GetEnumerator: IEnumerator<T>;
end;
var
IEnumerable<TMouse> mices = TStackoverflow<TMouse>.Create;
У меня будет реализация:
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;
Теперь, чтобы быть хорошим программистом, я выберу, что мой класс также будет поддерживать интерфейс IEnumerable:
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;
Те из вас, кто знает, где это происходит, будут знать, что реализация IEnumerable - это красная селедка; и это должно было быть сделано в любом случае.
Теперь возникает проблема
Этот код не компилируется, потому что:
function GetEnumerator: IEnumerator<T>;
function GetEnumerator: IEnumerator;
У меня есть два метода с одной и той же сигнатурой (не совсем одна и та же подпись, но такая же, что Delphi не может различать между ними):
E2254 Перегруженная процедура "GetEnumerator" должна быть отмечена директивой "перегрузка"
Хорошо, отлично, я буду отмечать их как overloads:
function GetEnumerator: IEnumerator<T>; overload;
function GetEnumerator: IEnumerator; overload;
Но это не работает:
E2252 Метод 'GetEnumerator' с идентичными параметрами уже существует
Разрешение метода интерфейса
Перегрузка была неправильным подходом, мы должны искать предложения о разрешении метода:
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;
Кроме того, это не скомпилируется ни по причинам, которые меня избегают:
E2291 Отсутствует реализация метода интерфейса IEnumerable.GetEnumerator
Итак, давайте забудем IEnumerable
Pretend Мне все равно, не поддерживает ли мой класс IEnumerable, удаляет его как поддерживаемый интерфейс. Это ничего не меняет, поскольку IEnumerable<T> происходит от IEnumerble:
IEnumerable<T> = interface(IEnumerable)
function GetEnumerator: IEnumerator<T>;
end;
поэтому метод должен существовать, а код, который удаляет 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;
не компилируется по той же причине:
E2291 Отсутствует реализация метода интерфейса IEnumerable.GetEnumerator
Хорошо, тогда забыть дженерики
Так что давайте остановимся, будем сотрудничать и слушать. IEnumerable вернулся как новое новое изобретение:
type
TStackoverflow = class(TInterfacedObject, IEnumerable)
public
function GetEnumerator: IEnumerator;
end;
{ TStackoverflow }
function TStackoverflow.GetEnumerator: IEnumerator;
begin
end;
Отлично, это работает. Я могу получить поддержку класса IEnumerable. Теперь я хочу поддерживать IEnumerable<T>.
Что приводит меня к моему вопросу:
Обновить: забыл приложить полный нефункциональный код:
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.