Delphi 中对象委托的共同祖先

Posted

技术标签:

【中文标题】Delphi 中对象委托的共同祖先【英文标题】:A common ancestor for of object delegates in Delphi 【发布时间】:2016-09-01 11:16:05 【问题描述】:

是否有一些用of object 子句声明的 Delphi 委托的共同祖先?

我需要为 TNotifyEvent 和我的自定义委托找到一个共同的祖先:

TMyEvent = procedure(Sender: TObject; msg: stringh); of object;

为触发这些事件制定通用方法。

我应该使用指针吗?还是 TObject?

【问题讨论】:

你能举个例子来说明你正在尝试做什么。现在看起来你好像在尝试通过调用方法而不提供所有需要的参数来打自己的脚。 我认为您错误地假设 procedure(sender: TObject) of objectprocedure(Sender: TObject; xyz: TSomehting) of object 在某种程度上兼容。他们不是!除非您在调用时具有正确的签名,否则您将传递以失败结尾的错误参数。 我很想提出一个使用泛型的解决方案。但是我没有足够的信息来制定完整的答案。您是否要创建一个TList<TEvent>,然后您可以拨打它;那是你想要做的吗?如果是这样,我对这个问题有一个简单的答案。 如果您想提出不同的问题,请这样做。我回到了第一个问题。 对不起@Paul,DH 有意见;将问题更改为给出的答案不再有意义是不好的形式。最好将更新后的 Q 复制粘贴到新 Q 中。 【参考方案1】:

您需要了解method pointers 的实现细节。这些存储为所谓的 双指针 值。一个指针指向方法调用的主体(实例),一个指针指向方法本身(代码)。

您可以使用来自System 单元的类型TMethod 来表示方法指针。它的声明看起来像这样(为简单起见,删除了比较运算符):

type
  TMethod = record
    Code, Data: Pointer;
  end;

您需要使用类型转换在这些类型之间进行分配:

uses
  System.Classes;

var
  Event: TNotifyEvent;
  Method: TMethod;

begin
  Method := TMethod(Event);
  TMethod(Event) := Method;
end.

显然这些都不是类型安全的,因此您需要确保正确性。编译器无法帮助您。没有什么比检查类型转换运算符as 更能处理方法指针了。也就是说,当您从TMethod 转换为特定的方法指针类型时,您必须确保TMethod 实例确实是您转换的方法指针类型的实例。将整个过程想象为类似于从类型化指针转换为非类型化指针,然后再返回。

现在,如果您要将任意方法指针存储到 TMethod 实例中,那很好。但是当您随后需要触发这些方法时会发生什么。您需要知道每个TMethod 实例背后真正的方法指针类型。这样您就知道如何转换它,它需要什么参数,以及如何调用它。这意味着您必须存储有关方法真实类型的额外信息,以及原始方法本身。

所以,我想我可能已经回答了您提出的问题,但我不确定它对您是否有用。要理解这一点,我认为我们确实需要更多地了解您想要实现的目标,以及您在何时拥有哪些信息。

例如,如果您知道要在需要存储时传递给方法的参数,则可以使用变量捕获并将其包装在匿名方法中。这将允许您保留类型安全并避免我在上面演示的任何相当可疑的转换。也许您需要partial application,作为调整非同质方法指针以具有相同接口的一种方式。在这种情况下,匿名方法又可以提供帮助。

【讨论】:

是的,没错。特别是考虑到类型安全,我认为你有前后左右的答案。您应该首先从类型安全选项开始,并且仅当该选项失败时建议使用 TMethod 类型的黑客。 也许吧,但我仍然不确定根本问题是什么,所以我专注于提出的实际问题。而且我不愿意花更多的时间在它已经做了相当多的事情! 答案提供了比需要更多的信息。简而言之:通过类型转换到 TMethod 放入列表,通过 PMyEvent(listItem)^ 从列表中调用 PMyEvent = ^TMyEvent. 不。那是不对的。您需要存储两个指针。答案包含所有信息。

以上是关于Delphi 中对象委托的共同祖先的主要内容,如果未能解决你的问题,请参考以下文章

阻止默认事件,事件委托和周期

JavaScript学习之事件委托

JavaScript性能优化之事件委托

Linux------Git-5

事件委托

spring静态代理