在一个文件中,我有一个带有ID属性的基类:
type
TBase = class
private
class function GetID(ACombo: TCombo): Integer; virtual;
class procedure SetID(ACombo: TCombo; AValue: Integer); virtual;
public
class property ID[ACombo: TCombo]: Integer read GetID write SetID;
end;
在第二个文件中,我有另一个类,从TBase下降。无论是偶然的,还是无知的,都是一个与现有财产/领域同名的新财产/领域。
type
TSubBase = class(TBase)
private
class function GetID(ACombo: TCombo): Integer; override;
class procedure SetID(ACombo: TCombo; AValue: Integer); override;
end;
并以下一种方式使用这些类:
TBaseClass = class of TBase;
function Base(): TBaseClass;
implementation
var
BaseInstance: TBaseClass;
function Base(): TBaseClass;
begin
if not Assigned(BaseInstance) then
begin
if SOME_PARAM then
BaseInstance:= TBase
else
BaseInstance:= TSubBase;
end;
Result := BaseInstance;
end;
if Base.StationCode[cmbStation] = SOME_VALUE then
但是我在编译时遇到了错误:
[DCC Error] uMyFile.pas(69): E2355 Class property accessor must be a class field or class static method
我一直在尝试使用静态关键字......并根据以下同事的建议找到了一些解决方法。
type
TBase = class
private
class function GetIDStatic(ACombo: TCombo): Integer; static;
class procedure SetIDStatic(ACombo: TCombo; AValue: Integer); static;
class function GetID(ACombo: TCombo): Integer; virtual; abstract;
class procedure SetID(ACombo: TCombo; AValue: Integer); virtual; abstract;
public
class property ID[ACombo: TCombo]: Integer read GetIDStatic write SetIDStatic;
end;
TSubBase = class(TBase)
private
class function GetID(ACombo: TCombo): Integer; override;
class procedure SetID(ACombo: TCombo; AValue: Integer); override;
end;
TBaseClass = class of TBase;
function Base(): TBaseClass;
implementation
var
BaseInstance: TBaseClass;
function Base(): TBaseClass;
begin
if not Assigned(BaseInstance) then
begin
if SOME_PARAM then
BaseInstance:= TBase
else
BaseInstance:= TSubBase;
end;
Result := BaseInstance;
end;
class function TBase.GetIDStatic(ACombo: TCombo): Integer; static;
begin
Result := BaseInstance.GetID(ACombo);
// Or maybe below ?
// Result := Base().GetID(ACombo);
end;
class procedure TBase.SetIDStatic(ACombo: TCombo; AValue: Integer); static;
begin
BaseInstance.SetID(ACombo, AValue);
// Or maybe below ?
// Base().SetID(ACombo, AValue);
end;
但是在最后一个变体中 - 实现是丑陋的,我同意大卫关于使用类属性和SIMPLY重构的方法留下“梦想”,如下所述:
class properties ID[ACombo: TCombo]: Integer ....
=>>
class function GetID(ACombo: TCombo): Integer; virtual;
class pocedure SetID(ACombo: TCombo; AValue: Integer); virtual;
感谢大家在那里挖掘乐趣!
答案 0 :(得分:3)
错误本身告诉:“类属性访问器必须是...... class static 方法”
你告诉过你可以编译TBase
,但是当你添加TSubBase
时会弹出错误。
但是不应该允许编译TBase
。如果是 - 那么Delphi中就有一个错误。
http://docwiki.embarcadero.com/RADStudio/XE5/en/Methods#Class_Methods
在类方法的定义声明中,标识符为Self 表示调用方法的类(可以是 定义它的类的后代。)如果方法是 在C类中调用,然后Self属于C的类型类。因此你 无法使用Self访问实例字段,实例属性和 正常(对象)方法。您可以使用Self来调用构造函数和 其他类方法,或访问类属性和类字段。
所以我们可以想到一些解决方法,明确说明我们想要调用方法的类。这样的事情:
class function GetIDStatic(ACombo: TCombo): Integer; static;
var RealClass: TBaseClass;
begin
RealClass := Self; /// will not compile !!!
Result := RealClass.GetID(ACombo);
end;
但是...
与普通的类方法不同,类静态方法根本没有Self参数
因此静态方法无法知道在调用站点调用了哪个类。因此,它们恰好称为函数体,在自己的类中定义。在这个地方 - 这将是一个抽象的功能。
然而,有一个明显的解决方法可以编写像
这样的东西if Base().n.StationCode[cmbStation] = SOME_VALUE then
然而,实施几乎没有效率,所以几乎不值得。
答案 1 :(得分:2)
编译器说:
类属性访问器必须是类字段或类静态方法
这意味着你运气不好。虽然可以实现virtual class methods,但它们不能用作类属性访问器。
documentation确实明确地说明了这一点:
可以在没有对象引用的情况下访问类属性。类属性访问器本身必须声明为类静态方法或类字段。
由此我们得出结论,类属性在编译时绑定到它们的访问器,并且根本没有可以产生运行时动态绑定的技巧。如果你想要多态行为,你将不得不使用类方法。