原始连接 http://rvelthuis.blogspot.tw/2018/01/accessing-private-methods-of-another.html

Accessing private methods of another class

 

In versions of Delphi before 10.1 Berlin, it was possible to access private members and private methods of a class simply by defining a class helper for it and accessing these private items in its methods.

But that it was so easy to access private members undermined the basic OO principles of information hiding and encapsulation. That is why this loophole (which could be considered a bug) was closed in Delphi 10.1 Berlin. But there was a lot of howling about this, because it was so easy and so convenient to have access to everything, even to other classes' "private parts".

There has been a lot of discussing going on about this. I will not repeat the arguments made there, but will state that I agree with the closing of the loophole. Accessing private members or methods is a hack, and a hack should never be easy. This hack was far too easy. Instead of using the hack, people should rather have tried to find other ways to achieve their goals.

But there is one argument of the pro-helper people that actually made sense: sometimes a class is not designed well, and you must resort to hacks.

Three hacks

They have all been mentioned before, in several blogs and StackOverflow answers, but I want to recap them here, in one post. All of these still require helper classes, as only there, you can still access private methods or members.

Accessing private methods

Say we have a class, let's call it THasPrivateMethods, that has at least one private method, let's say procedure PrivateMethod, that you want to call. The following three ways to call the private method have all been verified in Delphi 10.2.2 Tokyo. They should also work in previous versions.

Using assembler

The first way to get at private methods is to define a helper class with a new method. Here, I'll call the helper THelper and the first method CallingPrivateMethodUsingAsm. This method must be an assembler method:

type
THelper = class helper for THasPrivateMethods
public
procedure CallingPrivateMethodUsingAsm;
end;

The implementation is extremely simple:

procedure THelper.CallingPrivateMethodUsingAsm;
asm
JMP THasPrivateMethods.PrivateMethod
end;

In other words, in assembler, helper methods can still access private methods.

Using a method pointer

For those who are not very good with assembler, there is another, more tedious way, using a method pointer:

    procedure CallingPrivateMethodUsingTMethod; inline;

The implementation takes the address of the private method (which can apparently still be queried), puts it in a method pointer and then calls the method pointer:

type
TPrivateMethod = procedure of object; ... procedure THelper.CallingPrivateMethodUsingTMethod;
var
M: TMethod;
begin
M.Code := @THasPrivateMethods.PrivateMethod;
M.Data := Self;
TPrivateMethod(M);
end;

Using with

Inside a method of a class helper, you can't call a private method directly anymore, but you can use a simple trick (probably forgotten when they closed the loophole), using "with Self do". I am no fan of "with", but in this special case, it works as expected:

procedure THelper.CallingPrivateMethodUsingWith;
begin
with Self do PrivateMethod;
end;

Yes, it is that easy. But you must use "with Self do" to call the private method. Now, if you inline this method, there is absolutely no overhead. It will work as if you had called the private method in your own routine:

procedure NeedsAccessToPrivateMethod;
var
H: THasPrivateMethods;
begin
H := THasPrivateMethods.Create;
try
// ...
H.CallingPrivateMethodUsingWith;
// ...
finally
H.Free;
end;
end;

Again, if CallingPrivateMethodUsingWith is inlined, the resulting code is the same as if you had written:

  try
// ...
H.PrivateMethod;
// ...
finally

If you can read assembler, you can verify this in the CPU view of the IDE.

I will discuss accessing private fields in a later post.

附录: 根据上面的思路,搞定了如何取得私有属性的值。

Tmyclass=class
strict private i:integer;
procedure PrivateMethod;
public
constructor Create ;
end; TmyclassHelper = class helper for Tmyclass
public
procedure CallingPrivateMethodUsingAsm;
function getp:integer;
end; implementation {$R *.dfm} { TmyclassHelper } procedure TmyclassHelper.CallingPrivateMethodUsingAsm;
asm
JMP Tmyclass.PrivateMethod; end; function TmyclassHelper.getp: integer;
begin
with self do
result:=i; end; { Tmyclass } constructor Tmyclass.Create;
begin i:=;
end; procedure Tmyclass.PrivateMethod;
begin
showmessage('ok');
end; procedure TForm1.Button1Click(Sender: TObject);
var
c:Tmyclass; begin
c:=Tmyclass.Create;
c.CallingPrivateMethodUsingAsm; showmessage(c.getp.ToString);
end;

delphi 中如何访问另一个类中到私有方法?(转载)的更多相关文章

  1. Java中是否可以调用一个类中的main方法?

    前几天面试的时候,被问到在Java中是否可以调用一个类中的main方法?回来测试了下,答案是可以!代码如下: main1中调用main2的主方法 package org.fiu.test; impor ...

  2. @selector 如何调用在另一个类中的静态函数?

    可以在同一个类的methodName这个函数中再调用另一个类中的静态方法

  3. Java中的一个类怎么调用另一个类中的方法

    如果另一个类中的那个方法是私有的话,就不能直接调用到,如果是其他类型的话看情况,如果是静态的(static)话,直接用类名可以调用到,如果是非静态的,就需要利用另一个类的实例(也就是用那个类生成的对象 ...

  4. C#判断一个类中有无"指定名称"的方法

    C#中可以通过反射分析元数据来解决这个问题,示例代码如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 2 ...

  5. 在C#中我们能调用一个类的私有方法吗

    博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:在C#中我们能调用一个类的私有方法吗.

  6. Java反射机制demo(五)—获得并调用一个类中的方法

    Java反射机制demo(五)—获得并调用一个类中的方法 这个demo在使用反射机制操作属性之前,主要原因是因为在.class文件字节码中,方法排在属性的前面. 1,获得一个类中的方法 先看一下方法和 ...

  7. 为什么java中只允许继承一个类?

      一个类只能继承一个其他的类 在Java语言中禁止多重继承:一个类可以具有多个直接父类.多重继承不合法的原因是容易引发意义不明确.例如,有一个类C,如果允许它同时继承A类与B类(class C ex ...

  8. pytest之将多个测试用例放在一个类中,生成唯一临时文件夹

    将多个测试用例放在一个类中 简单来说就是将多个测试用例放到类中,通过pytest去管理,这和Testng很像.示例代码如下: """ 将多个测试用例放到一个类中执行 &q ...

  9. @Transactional-同一个类中方法自调,调用方法事物失效

    问题分析 一个类中的方法调用另一个事物传播性为创建事物的方法,调用的方法事物失效? SpringAOP 代理的Service对象调用了其方法,这个方法再去调用这个Service中的其他方法是没有使用A ...

随机推荐

  1. centos 6.5 DNS服务器 搭建

    一.DNS 介绍 DNS(Domain Name System,域名系统),因特网上作为域名和IP地址相互映射的一个分布式数据库,DNS协议运行在UDP协议之上,使用端口号53(Domain), 95 ...

  2. NumPy 矩阵库(Matrix)

    NumPy 矩阵库(Matrix) NumPy 中包含了一个矩阵库 numpy.matlib,该模块中的函数返回的是一个矩阵,而不是 ndarray 对象. 一个 的矩阵是一个由行(row)列(col ...

  3. tcp/ip通信第5期之客户机端程序

    /*此程序是tcp/ip通信的客户机端程序, 测试运行在redhat6系统上 重构readline函数,解决粘包问题——利用“\n”识别一个消息边界 */ #include<stdio.h> ...

  4. [剑指Offer]50-第一个只出现一次的字符

    题目链接 https://www.nowcoder.com/practice/1c82e8cf713b4bbeb2a5b31cf5b0417c?tpId=13&tqId=11187&t ...

  5. Wechat微信公众平台开发

    一.微信概述 1.历史背景 1)2011年1月21日,腾讯推出微信应用程序.(张小龙) 2)2012年8月20日,腾讯推出微信公众平台功能,同年11月开放第三方接口 3)2013年11月注册用户量突破 ...

  6. Java05-Java基础语法(四)循环结构

    Java05-Java基础语法(四)循环结构 循环结构(重复/迭代):根据条件重复执行部分语句 1.while循环结构 while(条件表达式){ 循环体语句; } 1)语法:a.while是关键字 ...

  7. 13-算法训练 P0505

    算法训练 P0505   时间限制:1.0s   内存限制:256.0MB      一个整数n的阶乘可以写成n!,它表示从1到n这n个整数的乘积.阶乘的增长速度非常快,例如,13!就已经比较大了,已 ...

  8. mysql 事务中如果有sql语句出错,会导致自动回滚吗?

    事务,我们都知道具有原子性,操作要么全部成功,要么全部失败.但是有可能会造成误解. 我们先准备一张表,来进行测试 CREATE TABLE `name` ( `id` int(11) unsigned ...

  9. mysql 中 replace into 与 insert into on duplicate key update 的使用和不同点

    replace into和insert into on duplicate key update都是为了解决我们平时的一个问题 就是如果数据库中存在了该条记录,就更新记录中的数据,没有,则添加记录. ...

  10. c#devexpres窗体划分 以及panelcontrol 相关操作

    想模仿flashfxp  做一个svn上传的客户端 左侧为本地目录,右侧为svn服务器目录 准备用devexpress 的 控件实现,顺便练习一下devexpress 相关使用. 1:要实现菜单栏工具 ...