我遇到了一个看似非常经典的问题:一个项目和一个集合类,它们都相互引用,需要一个前向声明.我正在使用Delphi 2010和更新5.
这适用于非泛型类,但我无法解决泛型类型的E2086错误:
type
// Forward declarations
TMyElement = class; // E2086: Type 'TMyElement' is not yet completely defined
TMyCollection<T:TMyElement> = class
//
end;
TMyElement = class
FParent: TMyCollection<TMyElement>;
end;
Run Code Online (Sandbox Code Playgroud)
切换类声明顺序时会发生同样的问题.
我在这里或在QualityCentral中没有找到任何对此问题的引用(发现了E2086的其他问题,但与此用例无关)
我现在唯一的解决方法是将父项声明为TObject,并在需要时将其强制转换为集合泛型类型(不是一个干净的解决方案......)
您是如何解决此问题,或者向前声明您的泛型类的?
谢谢,
[编辑2011年10月22日]跟进QualityCentral: 我在这里报告了质量中心的这个错误
EMB最近已经关闭,其解决方案状态如下:解决方案:已设计已解决的内容:16.0.4152
我只有Delphi 2010.有人可以确认它已在Delphe XE2 Update1中修复,还是意味着它按预期工作?
[编辑2011年10月23日] EMB的最终答案: EMB今天证实,实际的Delphi编译器不支持使用泛型类型的前向声明.你可以在QC中看到他们的回答,上面提供的链接.
我需要获取表单类型列表,但仅适用于从给定基本表单派生的类型.
我使用Delphi 2010和增强型RTTI来浏览类型
我目前的代码是:
rc := TRTTIContext.Create;
rtyps := rc.GetTypes;
for rtyp in rtyps do
begin
if not(rtyp.IsInstance) then Continue;
// Now I need to check if rtyp.AsInstance.MetaclassType is derived from TMyBaseForm
end;
Run Code Online (Sandbox Code Playgroud)
我不想实例化对象并使用'is'运算符,因为它不会及时执行.
作为当前的解决方法,我测试是否在RTTI上下文中找到了在TMyBaseForm中引入的方法:
if (rtyp.GetMethod('MyMethod') = nil) then Continue;
Run Code Online (Sandbox Code Playgroud)
但这不是一个干净的解决方案,因为如果在另一个类分支中引入了具有相同名称的方法,则会导致问题.
所以,我的问题是:是否有一种常规方法来检测类类型是否来自另一个类类型?
谢谢,
我已经定义了一个派生自TDictionary的集合,需要定义一个应用额外过滤器的自定义枚举器.
我被卡住,因为我无法访问TDictionary FItems数组(它是私有的)所以我无法定义MoveNext方法
您将如何继续重新定义从TDictionary派生的类的过滤枚举器?
这是一个简单的代码来说明我想要做的事情:
TMyItem = class(TObject)
public
IsHidden:Boolean; // The enumerator should not return hidden items
end;
TMyCollection<T:TMyItem> = class(TDictionary<integer,T>)
public
function GetEnumerator:TMyEnumerator<T>; // A value filtered enumerator
type
TMyEnumerator = class(TEnumerator<T>)
private
FDictionary: TMyCollection<integer,T>;
FIndex: Integer;
function GetCurrent: T;
protected
function DoGetCurrent: T; override;
function DoMoveNext: Boolean; override;
public
constructor Create(ADictionary: TMyCollection<integer,T>);
property Current: T read GetCurrent;
function MoveNext: Boolean;
end;
end;
function TMyCollection<T>.TMyEnumerator.MoveNext: Boolean;
begin
// In below code, FIndex is not accessible, so I can't …Run Code Online (Sandbox Code Playgroud) 我希望编译器在给定警告时停止,就像它是一个错误一样。
目标是强制考虑可能对代码真正有害的警告(并非每个警告在严重性方面都相等)
例如,我希望编译器停止此类警告:
我在IDE中找不到任何选项,也许在命令行编译器中找不到?
德尔福10.3.2
谢谢,
我需要浏览一些类的所有已发布属性.未列出类型为具有固定值的枚举的属性.
见下面的例子:
TMyEnum = (meBlue, meRed, meGreen);
TMyEnumWithVals = (mevBlue=1, mevRed=2, mevGreen=3);
TMyClass =
...
published
property Color: TMyEnum read FColor write SetColor; // This one is found
property ColorVal: TMyEnumWithVals read FColorVal write SetColorVal; // This one is never found
end;
Run Code Online (Sandbox Code Playgroud)
我需要固定值,因为这些属性存储在数据库中,我需要确保分配的值始终是相同的,无论下一版本中的Delphi编译器选择如何,并防止在枚举列表中任何错误的未来值插入.
我尝试使用新的Delphi 2010 RTTI(带.GetDeclaredProperties)和"旧"RTTI(带GetPropInfos):除上述类型的属性外,找到所有属性.
在所有类中都可以看到相同的行为.我还在一个示例项目中复制了这个.
尝试使用和不使用各种RTTI指令而不进行更改.
这是一个错误,一个已知的限制?是否有解决方法(除了删除枚举的固定值)?
使用Delphi2010 Ent + Update5
[编辑]答案下面提供变通方法:枚举的第一个值必须被设置为0而不是1,和值是连续的.经过测试和工作的解决方案
谢谢,
我有两个类:一个基类和一个派生类基类使用参数定义一个虚方法:
function ToName(MsgIfNil:string=''); virtual;
Run Code Online (Sandbox Code Playgroud)
派生类重新定义了该方法:
function ToName(MsgIfNil:string=''); reintroduce;
Run Code Online (Sandbox Code Playgroud)
这两种方法的实现类似于以下代码:
function TBaseClass.ToName(MsgIfNil:string)
begin
if (Self=nil) then
Result := MsgIfNil
else
Result := Self.SomeProperty;
end;
Run Code Online (Sandbox Code Playgroud)
问题是:
1)如果我没有在派生类中重新引入该方法,但使用常规override关键字,则对此方法的任何调用都会触发访问冲突
2)当我从一个nil的对象调用该方法,并且objet的假定类是TBaseObject时,它崩溃(AV)而不是调用基本虚方法
如果方法中没有定义参数,则调用正确的方法,不带任何AV.即使派生类中的方法被覆盖,它也能很好地工作.
请注意,上述解决方案适用于从TBaseClass派生的任何类的对象
如何定义可以使用Self = nil调用的虚拟方法,可以是虚拟的还是使用参数?
我当然必须加强对内部虚拟方法调用管道工程的理解......
注意:在我的用例中调用nil对象是合法的.它不用于隐藏异常,而是用于报告非链接对象.示例:myEdit.Text:= APerson.Manager.ToName('没有经理定义');
感谢您提供有关正确解决方案的任何建议
使用带有upd5的Delphi 2010
编辑:添加触发AV的更完整的代码示例
TBaseClass = class(TObject)
private
FMyName: string;
public
property MyName: string read FMyName;
function ToName(MsgIfNil:string=''):string; virtual;
end;
TDerivedClass = class(TBaseClass)
private
FSpecialName: string;
public
property SpecialName:string read FSpecialName;
function ToName(MsgIfNil:string=''):string; reintroduce;
end;
TBaseClass.ToName(MsgIfNil:string):string;
begin
if (Self=nil) then
Result := MsgIfNil
else
Result := …Run Code Online (Sandbox Code Playgroud)