Oop Delphi中实例化不同类型的通用机制
我试图使用泛型来“泛化”一个实例化不同类型网络传输的变量。我不确定“generic=no RTTI”规则是否会使该方法无效,因为我还没有跟上泛型的速度 我读过这篇文章: ,在问题中陈述如下: 如果可能的话,我想做的另一件事是改变两个 创作:Oop Delphi中实例化不同类型的通用机制,oop,delphi,generics,inheritance,Oop,Delphi,Generics,Inheritance,我试图使用泛型来“泛化”一个实例化不同类型网络传输的变量。我不确定“generic=no RTTI”规则是否会使该方法无效,因为我还没有跟上泛型的速度 我读过这篇文章: ,在问题中陈述如下: 如果可能的话,我想做的另一件事是改变两个 创作: LAdapter := TSQLiteNativeConnectionAdapter.Create(LFilename) LAdapter := TFireDacConnectionAdapter.Create(FDatabaseLink.FConnect
LAdapter := TSQLiteNativeConnectionAdapter.Create(LFilename)
LAdapter := TFireDacConnectionAdapter.Create(FDatabaseLink.FConnection as TFDConnection, FDatabaseLink.OwnedComponent)
在父类中使用抽象的“GetAdapterClass”类型函数
TModelDatabaseConnection,只需在
让孩子做一些类似的事情:
这正是我想做的。所以如果你能想象一下:
type
TTransport<T> = class(TComponent)
private
...
function GetTransport: TTransport;
procedure SetTransport(AValue: TTransport);
...
public
...
property Transport: TTransport read GetTransport write SetTransport;
...
end;
TTCPIPTransport = class(TTransport<T>)
private
function GetSocket(Index: Integer): String;
procedure SetSocket(Index: Integer; AValue: String);
public
property Socket[Index: Integer]: String read GetSocket write SetSocket;
end;
TServiceTransport = class(TTransport<T>)
private
function GetServiceName: String;
procedure SetServiceName(AValue: String);
public
property ServiceName: String read GetServiceName write SetServiceName;
end;
TISAPITransport = class(TServiceTransport<T>);
THTTPSysTransport = class(TServiceTransport<T>)
private
function GetURL(Index: Integer): String;
procedure SetURL(Index: Integer; AValue: String);
public
property URL[Index: Integer]: read GetURL write SetURL;
end;
etc.
类型
t传输=类(t组件)
私有的
...
功能GetTransport:ttTransport;
程序SetTransport(AValue:TTTRANSPORT);
...
公众的
...
属性传输:TTTransport读取GetTransport写入SetTransport;
...
结束;
TTCPIPTransport=类别(TTTransport)
私有的
函数GetSocket(索引:整数):字符串;
过程SetSocket(索引:整数;变量:字符串);
公众的
属性套接字[索引:整数]:字符串读取GetSocket写入SetSocket;
结束;
TServiceTransport=类别(TTransport)
私有的
函数GetServiceName:String;
过程SetServiceName(AValue:String);
公众的
属性ServiceName:字符串读取GetServiceName写入SetServiceName;
结束;
TISAPITransport=等级(TServiceTransport);
THTTPSystTransport=类别(TServiceTransport)
私有的
函数GetURL(索引:整数):字符串;
过程SetURL(索引:整数;变量:字符串);
公众的
属性URL[索引:整数]:读取GetURL写入SetURL;
结束;
等
其思想是创建一个基类,该基类具有所有传输所共有的所有字段/属性/方法,然后具有中间类,其中包含仅对传输的某个子集通用的字段/方法/属性,然后每个传输的最终版本特定于该类型
所以当我打电话时:
var
trans: TTransport<T> // or TTransport<TTCPIPTransport> etc.
begin
trans := TTransport<TTCPIPTransport>.Create(AOwner,....);
trans.Transport.Socket[0] := '127.0.0.1:8523';
OR
trans := TTransport<TISAPITransport>.Create(AOwner,...);
trans.Transport.ServiceName = 'Foo';
...
etc.
end;
var
运输:t运输//或t运输等。
开始
trans:=tttransport.Create(AOOwner,…);
传输套接字[0]:='127.0.0.1:8523';
或
trans:=tttransport.Create(AOOwner,…);
trans.Transport.ServiceName='Foo';
...
等
结束;
或者可能更通用,但是让每个trans实例(没有类型转换)自动显示特定于子类的属性/字段/方法
通过这种方式,我可以有一个配置屏幕,允许管理员选择传输类型,比如在组合框中,让变量值在in代码中设置类型,一组代码处理对象类型的创建
这可能是使用泛型吗?这是我在类工厂中的第一次(微弱的)尝试,以前从未这样做过。它可以部分工作(生成正确的类),但如果不进行类型转换,就不能作为基类的一个独特子类访问,这违背了它的目的。请参阅内联评论
TWSTransport = class(TComponent)
...
public
constructor Create(AOwner: TComponent); virtual;
....
end;
TWSTransportClass = Class of TWSTransport;
TWSTCPIPTransportClass = class of TWSTCPIPTransport;
TWSHTTPSysTransport = class(TWSServiceTransport);
TWSServiceTransport = class(TWSTransport);
TWSTransportStringConversion = class(TWSTransport);
TWSTransportStreamFormat = class(TWSTransportStringConversion);
TTransportFactory = class(TClassList)
private
function GetTransport(Index: TWSTransportClass; AOwner: TkbmMWServer): TWSTransportClass;
public
procedure RegisterTransportClass(ATransportClass: TWSTransportClass);
property Transport[Index: TWSTransportClass; AOwner: TkbmMWServer]: TWSTransportClass read GetTransport;
end;
function TTransportFactory.GetTransport(Index: TWSTransportClass; AOwner: TkbmMWServer): TWSTransportClass;
begin
if IndexOf(Index) > -1 then
Result := TWSTransportClass(Items[IndexOf(Index)])
else
Result := TWSTransportClass(Index.Create(AOwner));
end;
procedure TTransportFactory.RegisterTransportClass(ATransportClass: TWSTransportClass);
var
index: Integer;
begin
// is the transport registered?
index := IndexOf(ATransportClass);
if index < 0 then
// the transport is not registered, add it to the list
Add(ATransportClass);
end;
initialization
factory := TTransportFactory.Create;
factory.RegisterTransportClass(TWSHTTPSysTransport);
factory.RegisterTransportClass(TWSISAPIRESTTransport);
factory.RegisterTransportClass(TWSTCPIPTransport);
finalization
FreeAndNil(factory);
end.
所以我还是错过了一些东西。。。有人看到错误了吗?这里没有泛型的理由,至少从你给出的例子来看是这样。您的
ttcptptransport
已经是(更专业的版本)tttransport
,这是简单的继承/多态性,不需要任何T
。泛型的用途是在同一泛型类(类)内的方法的参数类型、方法的返回类型、属性类型或字段类型之间施加编译器强制的类型约束。泛型是编译时构造。您想在运行时选择类型。对不起,我只是不太熟悉。我想实例化一个泛型基类,并通过指定我想要的类型来获得一个更具体的类型,而不必对泛型基类实例进行类型转换,并且在基类变量实例中存在特定类的字段/属性/方法。泛型不是解决方案。您正在寻找的搜索表达式是类工厂。您的问题非常容易处理,并且可以很容易地解决。试图将泛型强制到运行时类型变体中只是一个错误。因为泛型是一个编译时构造。你应该解释为什么你发现泛型不合适,解释你发现了什么,解释为什么这段代码是一个更好的选择。在这里,仅仅将代码转储到答案空间并不能真正起作用;我发现了一个使用泛型来完成任务的项目。然而,在我的研究中,我也意识到D是如何在它自己的内部类工厂机制中使用TComponentClass等东西的,并且认为这是一种更好的方法,因为它避免了泛型的开销。但是,我还没有实现让工厂返回我的子类,并且只能够将其分配给子类实例而无需进行类型转换的目标:-(因为有人设法做到了这一点,但这并不意味着它是合适的。我敢肯定,在历史上的某个地方,有人设法用锤子敲打螺钉,让它固定住某个位置。这并不意味着锤子适合代替螺丝刀。:-)
TWSTransport = class(TComponent)
...
public
constructor Create(AOwner: TComponent); virtual;
....
end;
TWSTransportClass = Class of TWSTransport;
TWSTCPIPTransportClass = class of TWSTCPIPTransport;
TWSHTTPSysTransport = class(TWSServiceTransport);
TWSServiceTransport = class(TWSTransport);
TWSTransportStringConversion = class(TWSTransport);
TWSTransportStreamFormat = class(TWSTransportStringConversion);
TTransportFactory = class(TClassList)
private
function GetTransport(Index: TWSTransportClass; AOwner: TkbmMWServer): TWSTransportClass;
public
procedure RegisterTransportClass(ATransportClass: TWSTransportClass);
property Transport[Index: TWSTransportClass; AOwner: TkbmMWServer]: TWSTransportClass read GetTransport;
end;
function TTransportFactory.GetTransport(Index: TWSTransportClass; AOwner: TkbmMWServer): TWSTransportClass;
begin
if IndexOf(Index) > -1 then
Result := TWSTransportClass(Items[IndexOf(Index)])
else
Result := TWSTransportClass(Index.Create(AOwner));
end;
procedure TTransportFactory.RegisterTransportClass(ATransportClass: TWSTransportClass);
var
index: Integer;
begin
// is the transport registered?
index := IndexOf(ATransportClass);
if index < 0 then
// the transport is not registered, add it to the list
Add(ATransportClass);
end;
initialization
factory := TTransportFactory.Create;
factory.RegisterTransportClass(TWSHTTPSysTransport);
factory.RegisterTransportClass(TWSISAPIRESTTransport);
factory.RegisterTransportClass(TWSTCPIPTransport);
finalization
FreeAndNil(factory);
end.
procedure TForm4.FormCreate(Sender: TObject);
var
//trans: TWSTCPIPTransport; // this doesn't work
trans: TWSTransport; // this works
begin
trans := factory.Transport[TWSTCPIPTransport,Self];
showmessage(trans.classname); // this shows the correct classname - TWSTCPIPTransport
trans.AddSocket('127.0.0.1:80'); // the compiler gives an error here because this call is specific to a subclass of TWSTransport, TWSTCPIPTransport.
end;