我想创建一个结构如下的组件:
type
TCustomMyComp = class;
TMyComp = class;
TCustomSqlCommands = class;
TSqlCommands = class;
TFields = class;
TFieldsItem = class;
TFieldsSqlCommands = class;
TCustomMyComp = class(TComponent)
private
FFields: TFields;
FSqlCommands: TSqlCommands;
procedure SetFields(Value: TFields);
procedure SetSqlCommands(Value: TSqlCommands);
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
property Fields: TFields read FFields write SetFields;
property SqlCommands: TSqlCommands read FSqlCommands write SetSqlCommands;
end;
TCustomSqlCommands = class(TPersistent)
private
FOwner: TCustomMyComp;
FSelect: TStrings;
FInsert: TStrings;
FUpdate: TStrings;
FDelete: TStrings;
procedure SetSql(Index: Integer; Value: TStrings);
public
constructor Create(AOwner: TCustomMyComp); virtual;
destructor Destroy; override;
procedure Assign(Source: TPersistent); override;
published
property Select: TStrings index 0 read FSelect write SetSql;
property Insert: TStrings index 1 read FInsert write SetSql;
property Update: TStrings index 2 read FUpdate write SetSql;
property Delete: TStrings index 3 read FDelete write SetSql;
end;
[ComponentPlatformsAttribute(pidWin32 or pidWin64)]
TMyComp = class(TCustomMyComp)
published
property Fields;
property SqlCommands;
end;
TSqlCommands = class(TCustomSqlCommands)
published
property Insert;
property Update;
property Delete;
end;
//------- Fields -----------
TFields = class(TCollection)
private
FOwner: TCustomMyComp;
function GetItem(Index: Integer): TFieldsItem;
procedure SetItem(Index: Integer; Value: TFieldsItem);
protected
function GetOwner: TPersistent; override;
procedure Update(Item: TCollectionItem); override;
public
constructor Create(AOwner: TCustomMyComp);
function Add: TFieldsItem;
function Owner: TCustomMyComp;
end;
TFieldsItem = class(TCollectionItem)
private
FOwner: TCustomMyComp;
FSqlCommands: TFieldsSqlCommands;
procedure SetSqlCommands(Value: TFieldsSqlCommands);
protected
function GetDisplayName: String; override;
procedure SetIndex(Value: Integer); override;
public
constructor Create(Collection: TCollection); override;
destructor Destroy; override;
procedure Assign(Source: TPersistent); override;
published
property SqlCommands: TFieldsSqlCommands read FSqlCommands write SetSqlCommands;
end;
TFieldsSqlCommands = class(TCustomSqlCommands)
published
property Select;
property Insert;
end;我面临两个问题:
SqlCommands: TSqlCommands包含在TCustomSqlCommands下定义的所有属性,即使我定义为仅发布Insert,Update,Delete。Fileds->SqlCommands: TFieldsSqlCommands不包含任何属性,即使我将其定义为只发布Select,Insert。我做错了什么?
发布于 2017-04-27 16:03:06
TCustom...类将其属性定义为public或protected,但从不将其定义为published。这样,派生类就可以根据需要决定要将哪些属性提升到published。这将允许TSqlCommands不发布Select属性,允许TFieldsSqlCommands不发布Update和Delete属性。Fields属性是一个TFields对象(BTW,VCL已经在DB单元中有一个TFields类,因此您应该考虑将类重命名为更独特的类)。您的TFields类没有SqlCommands属性,而是TFieldsItem的属性。因此,您需要访问您的字段项之一,才能到达其SqlCommands属性。
但是,尽管TFields是TFieldsItem对象的集合,但您还没有声明一个属性来公开对TFieldsItem对象指针的直接访问(尽管您已经为该属性声明了getter/setter方法)。您正在从Items[]继承基本TCollection属性,并且该属性公开TCollectionItem对象指针,您必须将这些指针类型转换为TFieldItem。因此,您应该将自己的属性(任意命名)添加到TFields类中,以处理类型转换:
TFields = class(TCollection)私有..。函数GetField(索引:整数):TFieldsItem;过程SetField(索引:整数;值: TFieldsItem);公众..。属性FieldsIndex:整数: TFieldsItem读取GetField写入SetField默认值;
顺便说一句,由于TFields有一个Owner,所以您应该考虑从TOwnedCollection而不是直接从TCollection派生它。发布于 2017-04-27 08:18:52
我们是在讨论代码中的可见性吗?如果是,那么正确的做法是将所有属性视为公共属性,因为发布的属性具有相同的可见性。这两者之间唯一的区别是,已发布的属性包含在RTTI中,因此可以在对象检查器中看到它们。但是在代码中,您可以平等地访问公共属性和已发布的属性。
因此,如果您的第一个问题是从编码方面,这是正确的行为。
关于你的第二个问题:
如果从Fields实例访问TMyCustomComp属性,则不直接具有SqlCommands属性,因为您只能访问从TCollection继承的TFields对象。首先必须访问其中一个项,如果需要将其强制转换为TFieldsItem,则可以访问其SqlCommands属性。
在您的TCustomSqlCommands中,已经发布了这些属性,而在TFieldsSqlCommands中则再次发布了这些属性。我不知道这是否是一个问题,但也许您可以尝试在TCustomSqlCommands中公开它们,并将已发布的内容保存在TFieldsSqlCommands中。但是,由于它们的可见性,您仍然应该能够在代码中访问它们。
https://stackoverflow.com/questions/43651982
复制相似问题