Как реализовать 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.