Анонимные методы - это, по сути, interface
s с Invoke
методом:
type
TProc = reference to procedure;
IProc = interface
procedure Invoke;
end;
Теперь, есть ли возможность назначить их реальной переменной интерфейса или передать их как параметр интерфейса?
procedure TakeInterface(const Value: IInterface);
begin
end;
var
P: TProc;
I: IInterface;
begin
I := P; // E2010
TakeInterface(P); // E2010
end;
[Ошибка DCC32] E2010 Несовместимые типы: 'IInterface' и 'процедура, нетипизированный указатель или нетипизированный параметр'
Вопрос: каков будет вариант использования для этого?
Существует множество объектов, которые нельзя просто поддерживать с помощью ссылки на интерфейс. Поэтому они обертываются закрытием и уничтожаются вместе с ним, "Умные указатели" < / а>:
type
I<T> = reference to function : T;
TInterfaced<T: class> = class (TInterfacedObject, I<T>)
strict private
FValue: T;
function Invoke: T; // Result := FValue;
public
constructor Create(const Value: T); // FValue := Value;
destructor Destroy; override; // FValue.Free;
end;
IInterfacedDictionary<TKey, TValue> = interface (I<TDictionary<TKey, TValue>>) end;
TKey = String;
TValue = String;
var
Dictionary: IInterfacedDictionary<TKey, TValue>;
begin
Dictionary := TInterfaced<TDictionary<TKey, TValue>>
.Create(TDictionary<TKey, TValue>.Create);
Dictionary.Add('Monday', 'Montag');
end; // FRefCount = 0, closure with object is destroyed
Теперь иногда необходимо поддерживать не только один-единственный объект, но и контекст с ним. Представьте, что у вас есть TDictionary<TKey, TValue>
, и вы извлекаете из него счетчик: TEnumerator<TKey>
, TEnumerator<TValue>
или TEnumerator<TPair<TKey, TValue>>
. Или словарь содержит и владеет TObject
s. Тогда и новый объект, и закрытие словаря перейдут в новое закрытие, чтобы создать одну отдельную отдельную ссылку:
type
TInterfaced<IContext: IInterface; T: class> = class (TInterfacedObject, I<T>)
strict private
FContext: IContext;
FValue: T;
FFreeObject: Boolean;
function Invoke: T; // Result := FValue;
public
constructor Create(const Context: IContext; const Value: T; const FreeObject: Boolean = True); // FValue = Value; FFreeObject := FreeObject;
destructor Destroy; override; // if FFreeObject then FValue.Free;
end;
IInterfacedEnumerator<T> = interface (I<TEnumrator<T>>) end;
TValue = TObject; //
var
Dictionary: IInterfacedDictionary<TKey, TValue>;
Enumerator: IInterfacedEnumerator<TKey>;
Obj: I<TObject>;
begin
Dictionary := TInterfaced<TDictionary<TKey, TValue>>
.Create(TObjectDictionary<TKey, TValue>.Create([doOwnsValues]));
Dictionary.Add('Monday', TObject.Create);
Enumerator := TInterfaced<
IInterfacedDictionary<TKey, TValue>,
TEnumerator<TKey>
>.Create(Dictionary, Dictionary.Keys.GetEnumerator);
Obj := TInterfaced<
IInterfacedDictionary<TKey, TValue>,
TObject
>.Create(Dictionary, Dictionary['Monday'], False);
Dictionary := nil; // closure with object still held alive by Enumerator and Obj.
end;
Теперь идея состоит в том, чтобы объединить TInterfaced<T>
и TInterfaced<IContext, T>
, что сделало бы параметр типа для контекста устаревшим (интерфейса достаточно) и в результате получились бы следующие конструкторы:
constructor TInterfaced<T: class>.Create(const Value: T; const FreeObject: Boolean = True); overload;
constructor TInterfaced<T: class>.Create(const Context: IInterface; const Value: T; const FreeObject: Boolean = True); overload;
Быть (чистым) закрытием, возможно, не в первую очередь при работе с анонимными методами. Однако их типы могут быть заданы как интерфейс класса, объекты которого могут выполнять очистку при разрушении замыкания, а TFunc<T>
обеспечивает свободный доступ к его содержимому. Хотя у них нет общего предка, и кажется, что значения reference to
типов не могут быть присвоены типам интерфейсов, а это означает, что не существует единого, безопасного и надежного способа ссылаться на все типы замыканий, чтобы поддерживать их жизнь.
IInterface
для закрытия по сравнению с простой ссылкой на метод. Однако было интересно узнать, что вы можете писатьclass(TInterfacedObject, TProc)
, что определенно является для меня новостью! - person David Heffernan   schedule 09.07.2013