delphi 中如何访问另一个类中到私有方法?(转载)
原始连接 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 中如何访问另一个类中到私有方法?(转载)的更多相关文章
- Java中是否可以调用一个类中的main方法?
前几天面试的时候,被问到在Java中是否可以调用一个类中的main方法?回来测试了下,答案是可以!代码如下: main1中调用main2的主方法 package org.fiu.test; impor ...
- @selector 如何调用在另一个类中的静态函数?
可以在同一个类的methodName这个函数中再调用另一个类中的静态方法
- Java中的一个类怎么调用另一个类中的方法
如果另一个类中的那个方法是私有的话,就不能直接调用到,如果是其他类型的话看情况,如果是静态的(static)话,直接用类名可以调用到,如果是非静态的,就需要利用另一个类的实例(也就是用那个类生成的对象 ...
- 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 ...
- 在C#中我们能调用一个类的私有方法吗
博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:在C#中我们能调用一个类的私有方法吗.
- Java反射机制demo(五)—获得并调用一个类中的方法
Java反射机制demo(五)—获得并调用一个类中的方法 这个demo在使用反射机制操作属性之前,主要原因是因为在.class文件字节码中,方法排在属性的前面. 1,获得一个类中的方法 先看一下方法和 ...
- 为什么java中只允许继承一个类?
一个类只能继承一个其他的类 在Java语言中禁止多重继承:一个类可以具有多个直接父类.多重继承不合法的原因是容易引发意义不明确.例如,有一个类C,如果允许它同时继承A类与B类(class C ex ...
- pytest之将多个测试用例放在一个类中,生成唯一临时文件夹
将多个测试用例放在一个类中 简单来说就是将多个测试用例放到类中,通过pytest去管理,这和Testng很像.示例代码如下: """ 将多个测试用例放到一个类中执行 &q ...
- @Transactional-同一个类中方法自调,调用方法事物失效
问题分析 一个类中的方法调用另一个事物传播性为创建事物的方法,调用的方法事物失效? SpringAOP 代理的Service对象调用了其方法,这个方法再去调用这个Service中的其他方法是没有使用A ...
随机推荐
- zabbix 自定义监控 排除带报错提示
UserParameter=lq_data_sqoop,/usr/local/bin/sqoop.sh 2>/dev/null |awk '{print $2}' 注意:2>/dev/n ...
- 反转链表(python)
题目描述 输入一个链表,反转链表后,输出新链表的表头. # -*- coding:utf-8 -*- # class ListNode: # def __init__(self, x): # self ...
- Gym - 101911C Bacteria (规律题)
传送门:点我 Time limit2000 ms Memory limit262144 kB Recently Monocarp has created his own mini-laboratory ...
- Codeforces Beta Round #52 (Div. 2)
Codeforces Beta Round #52 (Div. 2) http://codeforces.com/contest/56 A #include<bits/stdc++.h> ...
- 【laravel VS lumen】
读取项目的配置信息 读取config文件database.php中的default属性信息 laravel:config('database.default'); lumen:app()->co ...
- sql语句Order by 报错列名不明确
select top 10 column1,column2,column3 from table1 where table1.id not in(select top 0 table1.id from ...
- FragmentManager V4包下 应该用FragmentActivity
import android.os.Bundle; import android.support.v4.app.FragmentActivity; public class MainActivity ...
- idea工程中web.xml报错Servlet should have a mapping
搭建ssm工程过程中web.xml报错:Servlet should have a mapping ....但是mapping已经配置好了...如下图: 搜索无果,后来发现是工程的web.xml位置配 ...
- xshell实时跟踪日志与中文乱码设置
1.实时跟踪日志命令 tail -f logName.log 动态查看名为logName的日志信息 ctrl+c 退出实时跟踪 2.中文乱码设置 在Xshell.putty.SSH Secure Sh ...
- iOS | 使用HBuilder进行云端打包步骤
1.先在HBuilder本地项目中的Manifest.json文件中进行项目配置,将应用的图标和启动图,按照固定的尺寸进行配置.设置应用名称,版本号, 这里的appid不需要修改,是HBuilder自 ...