这是一个后续问题:如何隐藏对象的受保护过程?
(我对整个班助手概念有点模糊)
假设我有一个类:
type
TShy = class(TObject)
strict private
procedure TopSecret;
private
procedure DirtyLaundry;
protected
procedure ResistantToChange;
end;
Run Code Online (Sandbox Code Playgroud)
我知道如果我通过在同一单元中添加一个后代类来获得源代码,我可以访问私有方法.
我有两个问题:
- 如何使用班助手访问strict private会员?
- 我可以在一个单独的单元中使用类助手来访问(严格)私有成员吗?
我需要访问一个严格的受保护属性,因为我需要创建一个验证(基于此属性的值)以避免错误.(我没有具有此属性的第三方类的源代码)只有我有类(接口)和dcu的定义(所以我无法更改属性可见性).问题是存在一种访问严格受保护财产的方法吗?(我真正读懂了Hallvard Vassbotn博客,但我不觉得这个特定主题参选.)
我创建了这个帮助器,以便为该string类型添加更多功能:
type
AStringHelper = record helper for string
function Invert: string; overload;
function InvertMe: string; overload;
end;
Run Code Online (Sandbox Code Playgroud)
但是当我在我的代码中使用它时,TStringHelperin System.StrUtils"out out"并且我无法使用它的函数.
它们可能共存吗?
Delphi 8引入了类助手,用于将VCL/RTL映射到.NET对象层次结构.它们允许将方法注入到现有类中,而不会覆盖类或修改原始类.后来的Delphi版本发现了类帮助程序的改进,并将它们移植到Win32.
在帮助中,它说:"在开发新代码时,不应将它们视为一种设计工具."
班级助手违反了传统的OOP,但我认为这不会使他们成为一件坏事.这个警告是否合理?
在开发新代码时是否应该使用类助手?
在开发新代码时是否使用它们?
为什么或者为什么不?
Per Malcolm的评论:新代码意味着每日应用程序开发,你有一些第三方库,一些现有代码,然后是你正在编写的代码.
我想使用Gabriel Corneanu的jpegex,jpeg.TJPEGImage的类助手.阅读这个和这个,我了解到,超过德尔福西雅图你不能访问私有字段不再像jpegex确实(在下面的例子中FDATA).和David Heffernan提出的VMT一样,远远超出我的范围.有没有更简单的方法来完成这项工作?
type
// helper to access TJPEGData fields
TJPEGDataHelper = class helper for TJPEGData
function Data: TCustomMemoryStream; inline;
procedure SetData(D: TCustomMemoryStream);
procedure SetSize(W,H: integer);
end;
// TJPEGDataHelper
function TJPEGDataHelper.Data: TCustomMemoryStream;
begin
Result := self.FData;
end;
Run Code Online (Sandbox Code Playgroud) 我正在使用Delphi 2009.是否可以为泛型类编写一个类助手,即用于TQueue.显而易见的
TQueueHelper <T> = class helper of TQueue <T>
...
end;
Run Code Online (Sandbox Code Playgroud)
不起作用,也不起作用
TQueueHelper = class helper of TQueue
...
end;
Run Code Online (Sandbox Code Playgroud) 所有文档版本(包括最新版本)都提供以下类/记录帮助程序语法:
type
identifierName = class|record helper [(ancestor list)] for TypeIdentifierName
memberList
end;
Run Code Online (Sandbox Code Playgroud)
它只解释了什么......
祖先列表是可选的.它只能为类助手指定.
......并且不再进入可怕的细节.其余文档主题中的用法示例仅仅是利用ancestor list可选的事实.我见过的所有EMBA代码以及所有第三方代码都没有使用这一ancestor list部分.
所以,我的问题在标题中列出:
ancestor list类助手语法的目的是什么?让我们说我有一个示例类助手
TSampleClassHelper = class helper for TSampleClass
public
procedure SomeHelper;
end;
Run Code Online (Sandbox Code Playgroud)
我做以下事情:
var
obj :TSampleClass;
begin
obj:=TSampleClass.Create;
obj.SomeHelper;
end;
Run Code Online (Sandbox Code Playgroud)
这按预期工作.
但是,如何使用RTTI来调用辅助方法呢?以下似乎不起作用,GetMethod返回nil.
var
obj :TSampleClass;
ctx :TRTTIContext;
rtype :TRTTIType;
rmethod :TRTTIMethod;
begin
obj:=TSampleClass.Create;
rtype:=ctx.GetType(obj.ClassType);
rmethod:=rtype.GetMethod('SomeHelper'); // rmethod is nil !
end;
Run Code Online (Sandbox Code Playgroud)
那么RTTI不适用于类助手中定义的方法吗?有没有办法解决?
谢谢.
我有很少的类助手用于创建子组件,如弹出菜单,以便在运行时访问这些子组件,我创建了一个Singleton TDictionary.
我的问题是如何知道所有者组件被销毁以从TDictionary中删除子组件?
如果它是一个专门的组件,我将它添加到析构函数中,但我不能在类助手中添加构造函数和/或析构函数.
编辑 - 解决方案
我创建了一个接受TObject作为参数的基础对象,使用时,必须手动完成删除操作.
然后我从它继承了一个新类,重写方法只接受TComponent.这就是现在代码的相关部分:
type
TCustomLinkedComponents = class(TCustomLinkedObjects)
strict private
type
TCollector = class(TComponent)
protected
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
end;
strict private
FCollector: TCollector;
[..]
end;
procedure TCustomLinkedComponents.Add(Owner: TComponent; const LinkedName: string; LinkedComponent: TComponent);
begin
inherited Add(Owner, LinkedName, LinkedComponent);
FCollector.FreeNotification(LinkedComponent);
end;
procedure TCustomLinkedComponents.TCollector.Notification(AComponent: TComponent; Operation: TOperation);
begin
inherited;
if Operation = opRemove then
LinkedObjects.Remove(TObject(AComponent));
end;
Run Code Online (Sandbox Code Playgroud)
使用这种方法,我可以解决我的实际需要,并打开后可以轻松扩展.
有System.SysUtils.TShortIntHelper(和其他人)我可以写:
output := 5.ToString();
Run Code Online (Sandbox Code Playgroud)
将数字格式化5为string.同样,有System.SysUtls.TExtendedHelper,但我无法编译:
output := (5.0).ToString();
Run Code Online (Sandbox Code Playgroud)
E2018:需要记录,对象或类类型
其他不起作用的版本:
5.0.ToString()(1.0+5.1).toString()(5+0.).toString() (说E2029:')'预期但'''找到了)实际工作的版本:
(1+5.1).toString()(1.1+1+5.1).toString()5.9e0.toString()如果声明了扩展值const,它也不起作用:
function TestFormat(): String;
const
q = 5.5;
begin
Result := q.ToString();
end;
Run Code Online (Sandbox Code Playgroud)
但它的定义是q : extended = 5.5;有效的.所以,我想知道为什么编译器会以这种方式运行.
我需要使用他的实例和变量的偏移来访问类的严格私有类var值.
到目前为止尝试了这个,检查这个示例类
type
TFoo=class
strict private class var Foo: Integer;
public
constructor Create;
end;
constructor TFoo.Create;
begin
inherited;
Foo:=666;
end;
//this function works only if I declare the foo var as
//strict private var Foo: Integer;
function GetFooValue(const AClass: TFoo): Integer;
begin
Result := PInteger(PByte(AClass) + 4)^
end;
Run Code Online (Sandbox Code Playgroud)
如您所见,函数GetFooValue仅在foo变量未声明为类var时才起作用.
问题是我必须如何修改 GetFooValue才能获得Foo声明时的值strict private class var Foo: Integer;
假设我们有一个方法的类可能非常有用,但是由于受保护范围不可用:
unit Sealed;
interface
type
TGeneral = class(TObject)
{ this method is useful, but not available }
protected procedure Useful; virtual;
end;
TSpecific1 = class(TGeneral)
{ some descendants override `Useful` method }
protected procedure Useful; override;
end;
TSpecific2 = class(TGeneral)
{ and some dont, but inherit `Useful`ness from the parent }
end;
Run Code Online (Sandbox Code Playgroud)
我知道有两种老派的方式来接触这种方法,两者都涉及继承和类型转换.两种方法都应该与基本情况#1和高级多态情形#2相同.
program CallingSite;
uses Sealed;
function GetInstance: TGeneral;
begin
{ !PSEUDO! makes compiler happy about the rest of code }
// depending on use case supposed to return …Run Code Online (Sandbox Code Playgroud) class-helpers ×13
delphi ×13
delphi-xe ×2
oop ×2
rtti ×2
delphi-2009 ×1
delphi-2010 ×1
generics ×1
lifecycle ×1
pointers ×1