Oop Delphi中实例化不同类型的通用机制

Oop Delphi中实例化不同类型的通用机制,oop,delphi,generics,inheritance,Oop,Delphi,Generics,Inheritance,我试图使用泛型来“泛化”一个实例化不同类型网络传输的变量。我不确定“generic=no RTTI”规则是否会使该方法无效,因为我还没有跟上泛型的速度 我读过这篇文章: ,在问题中陈述如下: 如果可能的话,我想做的另一件事是改变两个 创作: LAdapter := TSQLiteNativeConnectionAdapter.Create(LFilename) LAdapter := TFireDacConnectionAdapter.Create(FDatabaseLink.FConnect

我试图使用泛型来“泛化”一个实例化不同类型网络传输的变量。我不确定“generic=no RTTI”规则是否会使该方法无效,因为我还没有跟上泛型的速度

我读过这篇文章:

,在问题中陈述如下:

如果可能的话,我想做的另一件事是改变两个 创作:

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;