我正在尝试为复合控件构建一个通用的祖先.最初的想法看起来像这样:
type
TCompositeControl<TControl1: TControl; TControl2: TControl> = class(TWinControl)
private
FControl1,
FControl2: TControl;
public
constructor Create(AOwner: TComponent); override;
end;
TLabelAndEdit = TCompositeControl<TLabel, TEdit>; // simple example for illustration only
constructor TCompositeControl<TControl1,TControl2>.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FControl1 := TControl1.Create(Self);
FControl2 := TControl2.Create(Self);
end;
Run Code Online (Sandbox Code Playgroud)
您可能已经知道,这将触发编译器错误E2568:无法在类型参数声明中创建没有CONSTRUCTOR约束的新实例.constructor然而,添加约束并没有帮助,因为它意味着无参数构造函数.
转换模板以TControl使代码可编译:
...
FControl1 := TControl(TControl1).Create(Self);
...
Run Code Online (Sandbox Code Playgroud)
...但它会在运行时导致访问冲突.
一个可能有用的黑客是通过RTTI调用构造函数,但我认为这是一个相当脏的解决方案.
另一个基本上有效的黑客是使用类类型变量作为中间体:
type
TControlClass = class of TControl;
constructor TCompositeControl<TControl1,TControl2>.Create(AOwner: TComponent);
var
lCtrlClass1,
lCtrlClass2: TControlClass;
begin
inherited Create(AOwner);
lCtrlClass1 := TControl1;
FControl1 := lCtrlClass1.Create(Self);
lCtrlClass2 := TControl2; …Run Code Online (Sandbox Code Playgroud) delphi generics polymorphism constructor generic-constraints
我最近偶然发现了一些由我编写的非常旧的代码引起的问题,这显然假设一个with语句中使用的接口引用会在with-block被保留后立即释放- 有点像一个隐式try-finally块(类似于C#的using-statement)如果我理解正确的话).
显然(在Delphi 2009中)这不是(不再是?)的情况.有谁知道这发生的时间?或者我的代码开始时是完全错误的?
为了澄清,这是一个简化的例子:
type
IMyIntf = interface;
TSomeObject = class(TInterfacedObject, IMyIntf)
protected
constructor Create; override; // creates some sort of context
destructor Destroy; override; // cleans up the context created in Create
public
class function GetMyIntf: IMyIntf; //a factory method, calling the constructor
end;
procedure TestIt;
begin
DoSomething;
with (TSomeObject.GetMyIntf) do
begin
DoStuff;
DoMoreStuff;
end; // <- expected: TSomeObject gets destroyed because its ref.count is decreased to 0
DoSomethingElse;
end; …Run Code Online (Sandbox Code Playgroud) delphi interface reference-counting delphi-2009 with-statement
我刚刚将几个自制的Outlook COM-addins从Delphi 2007移植到Delphi 2009,现在我遇到了一些非常奇怪的错误(在你问之前:没有一个看起来与字符串处理有任何明显的关系),例如模式对话框,当一个人试图再次调用它们时挂起Outlook(第一次看起来很好),但只有当它们从一个特定的事件处理程序调用而不是在其他地方做同样的事情时.当我将错误跟踪到特定的代码行并注释掉该行或用不同的代码将其替换为相同的效果时(例如,通过将代码通过函数直接调用到调用站点),将出现错误离开 - 通常只是为了稍后再发表一些(同样不显眼的)陈述.
在Delphi调试器中运行时,我可以看到冻结通常在访问冲突之前GetMem.inc.至少所有这些问题都是100%可重复的......
毋庸置疑,在Delphi 2007中编译这些插件时,我们没有遇到任何这些问题.
现在,我很茫然.我知道我很幸运,但即使我认为自己是一个相当有经验的程序员(虽然主要是在利基领域),我从来没有真正处理过这类错误.正如这个问题的标题所说,我甚至不知道从哪里开始.我可以尽可能多地浏览代码,但无限的汇编语句对我来说毫无意义,我也不熟练有效地使用CPU视图.
此外,我甚至不确定这是否是我自己的代码开头的问题(在这种情况下我实际上倾向于怀疑).我们大量使用了许多第三方库(例如JCL,ADX,Redemption).ADX特别指出其Delphi 2009支持"beta".
我也尝试过使用FastMM的FullDebugMode,事实上我确实发现了ADX中的一些错误(例如,在被释放后被修改的块)但是当我使用Delphi 2007进行编译时所有这些也会发生,所以它似乎还不是很有必要这些最终是观察到的回归的原因.
那么,我该如何处理呢? - 或者更好的是:我在哪里可以找到一些学习如何处理这个问题的好资源?例如,有关使用CPU视图或有效解释和处理FastMM提交的报告的教程?这些都是正确的工具吗?我还应该在哪儿看?
附录:
在这种情况下,我应该怀疑哪些类型的代码?什么样的代码甚至有可能在内存中造成这样的破坏?我可以想到我的代码执行远程接近显式内存操作的任何地方的唯一地方是在准备WinAPI调用时保留一些缓冲区空间.还要记住,我的所有代码在Delphi 2007和Delphi 2009版本之间是相同的,Delphi 2007版本没有出现这样的问题.
更新:
有一些概率,促使我发布此问题的问题现已解决.请看下面我自己的答案.
delphi ×3
delphi-2009 ×2
com ×1
constructor ×1
debugging ×1
generics ×1
identity ×1
interface ×1
polymorphism ×1