匿名方法本质上是带有Invoke
方法的interface
:
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'和'程序,不具型别指标或不具型别参数'
问题:此功能的使用情形是什么?
有很多对象不能简单地通过接口引用来保持活动状态,因此它们被 Package 在闭包中并被销毁,"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>
,这将使上下文的类型参数过时(一个接口就足够了),并产生以下构造函数:
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
类型的值似乎不能被分配给接口类型,这意味着,没有统一的、安全的和未来的方法来引用所有类型的闭包以使它们保持活动。
3条答案
按热度按时间rkue9o1l1#
这很简单,我给你两条路.
另一种方法是声明PInterface
tpxzln5u2#
据我所知,你不能做你需要的铸造。
我想,你可以用
Move
来做一个赋值:老实说,我不知道这有多健壮。它能在多个 Delphi 版本上工作吗?依赖晦涩的未记录的实现细节是明智的吗?只有你能确定你所获得的收益是否超过依赖实现细节所带来的负面影响。
b4wnujal3#
最简单的转换方法如下: