delphi - 将匿名方法分配给接口(interface)变量或参数?

标签 delphi closures anonymous-methods

匿名方法本质上是 interface s 带有 Invoke方法:

type
  TProc = reference to procedure;

  IProc = interface
    procedure Invoke;
  end;

现在,是否可以将它们分配给实际的接口(interface)变量或将它们作为接口(interface)参数传递?

procedure TakeInterface(const Value: IInterface);
begin
end;

var
  P: TProc;
  I: IInterface;
begin
  I := P; // E2010
  TakeInterface(P); // E2010
end;

[DCC32 错误] E2010 不兼容的类型:“IInterface”和“过程、无类型指针或无类型参数”

问题:这有什么用例?

有很多对象不能简单地通过接口(interface)引用来保持事件状态。因此,它们被包裹在一个封闭物中并随之被破坏,"Smart Pointers" :

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> ,这将使上下文的类型参数过时(一个接口(interface)就足够了)并导致这些构造函数:

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;

作为(纯)闭包可能不是人们在使用匿名方法时想到的主要用途。但是,它们的类型可以作为类的接口(interface)给出,该类的对象可以在闭包销毁时进行清理,并且 TFunc<T>使其能够流畅地访问其内容。不过,它们没有共同的祖先,并且值似乎为 reference to类型不能分配给接口(interface)类型,这意味着没有统一、安全且面向 future 的方法来引用所有类型的闭包以保持它们的活力。

最佳答案

这非常简单。我将向您展示两种方法。

var
  P: TProc;
  I: IInterface;
begin
  I := IInterface(Pointer(@P)^);
  TakeInterface(I);
end;

另一种方法是声明 PInterface

type
  PInterface = ^IInterface;
var
  P: TProc;
  I: IInterface;
begin
  I := PInterface(@P)^;
  TakeInterface(I);
end;

关于delphi - 将匿名方法分配给接口(interface)变量或参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17533381/

相关文章:

delphi - Delphi 中函数重载有运行时开销吗?

java - 从 grails 闭包返回特定值

c# - 如何从匿名定义的事件处理程序中提取 "real"目标?

windows - 如何在delphi中使用ToastGeneric创建toast通知

sql - Delphi中从sql server表动态创建弹出菜单树

delphi - 关闭并重新启动DELPHI中的当前应用程序

javascript - 访问函数内的成员/从外部设置它们

testing - 如何处理将可变借用的结构传递给函数闭包?

iphone - 是否可以在 Objective-C 中定义匿名选择器?

c# - Invoke调用中的匿名方法