jpf*_*ius 8 delphi generics delphi-2009 class-helpers
我正在使用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)
Del*_*ics 13
正如Delphi帮助中所记录的那样,类助手不是为通用目的而设计的,并且它们被错误地认为具有许多限制甚至是错误.
然而,在我看来,有一种观念 - 不正确和危险 - 这些是通用"工具包"中的合法工具.我在博客上写了为什么这是错误的,随后关于你如何通过遵循社会责任编码模式来减轻危险(尽管这不是防弹).
通过对从您尝试扩展的类派生的"伪"类进行硬强制转换,您可以实现类帮助程序的效果,而不会出现任何这些错误或限制或(最重要的)风险.即代替:
TFooHelper = class helper for TFoo
procedure MyHelperMethod;
end;
Run Code Online (Sandbox Code Playgroud)
使用
TFooHelper = class(TFoo)
procedure MyHelperMethod;
end;
Run Code Online (Sandbox Code Playgroud)
就像使用"正式"帮助器一样,你永远不会实例化这个TFooHelper类,只使用它来改变TFoo类,除非在这种情况下你必须是显式的.在您的代码中,当您需要使用"帮助"方法使用TFoo的某个实例时,您必须进行强制转换:
TFooHelper(someFoo).MyHelperMethod;
Run Code Online (Sandbox Code Playgroud)
缺点:
你必须坚持适用于帮助者的相同规则 - 没有成员数据等(根本不是真正的缺点,除了编译器不会"提醒你").
你必须明确地转换为使用你的助手
如果使用辅助揭露保护成员必须(除非您公开暴露所需的保护成员的公共方法)宣布在你使用它在同一单元的帮手
好处:
如果您开始使用其他"帮助"相同基类的代码,那么您的帮助程序绝对没有风险
显式类型转换使你的"消费者"代码清楚地表明你正在以类本身不直接支持的方式使用类,而不是捏造并隐藏一些语法糖背后的事实.
它并不像班级助手一样"干净",但在这种情况下,"清洁"的方法实际上只是把地毯弄得乱七八糟,如果有人打扰地毯,你最终会陷入比你开始时更大的混乱.
Ken*_*ran 12
我目前仍然使用Delphi 2009,所以我想我会添加一些其他方法来扩展泛型类.这些应该在较新版本的Delphi中同样有效.让我们看看将一个ToArray
方法添加到List类会是什么样子.
拦截器类是与它们继承的类同名的类:
TList<T> = class(Generics.Collections.TList<T>)
public
type
TDynArray = array of T;
function ToArray: TDynArray;
end;
function TList<T>.ToArray: TDynArray;
var
I: Integer;
begin
SetLength(Result, self.Count);
for I := 0 to Self.Count - 1 do
begin
Result[I] := Self[I];
end;
end;
Run Code Online (Sandbox Code Playgroud)
请注意,您需要使用完全限定名称Generics.Collections.TList<T>
作为祖先.否则你会得到E2086 Type '%s' is not completely defined
.
这种技术的优点是你的扩展大多是透明的.您可以在使用原始文件的任何位置使用新TList的实例.
这种技术有两个缺点:
通过仔细的单元命名并避免在与拦截器类相同的位置使用"原始"类,可以减轻混淆.在Embarcadero提供的rtl/vcl类中,密封类不是很大的问题.我只在整个源代码树中找到了两个密封版:TGCHandleList(仅用于现已解散的Delphi.NET)和TCharacter.但是,您可能会遇到与第三方库有关的问题.
装饰器模式允许您通过使用继承其公共接口的另一个类包装它来动态扩展类:
TArrayDecorator<T> = class abstract(TList<T>)
public
type
TDynArray = array of T;
function ToArray: TDynArray; virtual; abstract;
end;
TArrayList<T> = class(TArrayDecorator<T>)
private
FList: TList<T>;
public
constructor Create(List: TList<T>);
function ToArray: TListDecorator<T>.TDynArray; override;
end;
function TMyList<T>.ToArray: TListDecorator<T>.TDynArray;
var
I: Integer;
begin
SetLength(Result, self.Count);
for I := 0 to Self.Count - 1 do
begin
Result[I] := FList[I];
end;
end;
Run Code Online (Sandbox Code Playgroud)
再一次有优点和缺点.
好处
缺点
边注
所以看起来如果你想让一个类几乎不可能扩展,那就让它成为一个密封的泛型类.然后类帮助程序无法触及它,也无法继承它.关于剩下的唯一选择是包装它.
就像我所知道的那样,没有办法将类助手放在泛型类上并进行编译.您应该将此报告给QC作为错误.