德尔福:泛型和'是'运算符问题

时间:2009-11-19 07:23:31

标签: delphi generics casting

基于早期的post,我编写了以下代码。请原谅这篇文章的详细内容。我相信所有各方都可以使用完整的代码进行测试和评论。

program sandbox;
{$APPTYPE CONSOLE}

uses
  SysUtils,
  Generics.Collections;

type
  TDataType = class
    // Stuff common to TInt and TStr
  end;

  TInt = class(TDataType)
    FValue:  integer;
    constructor Create(Value, Low, High: integer);
  end;

  TStr = class(TDataType)
    FValue: string;
    constructor Create(Value: string; Length: integer);
  end;

  TSomeClass = class
    FIntList: TList<TInt>;
    FStrList: TList<TStr>;
    procedure AddToList<T: TDataType>(Element: T);
    constructor Create();
    procedure Free();
  end;

constructor TInt.Create(Value, Low, High: Integer);
begin
  inherited Create();
  FValue := Value;   
end;

constructor TStr.Create(Value: string; Length: Integer);
begin
  inherited Create();
  FValue := Value;
end;

procedure TSomeClass.AddToList<T>(Element: T);
begin
  if TObject(Element) is TInt then
    FIntList.Add(Element)
  else if TObject(Element) is TStr then
    FStrList.Add(Element);
end;

constructor TSomeClass.Create();
begin
  inherited;
  FIntList := TList<TInt>.Create();
  FStrList := TList<TStr>.Create();
end;

procedure TSomeClass.Free();
var
  SomeIntItem: TInt;
  SomeStrItem: TStr;
begin
  for SomeIntItem in FIntList do begin
    SomeIntItem.Free();
  end;

  for SomeStrItem in FStrList do begin
    SomeStrItem.Free;
  end;

  FIntList.Free();
  FStrList.Free();
end;

var
  Inst: TSomeClass;

begin
  try
    { TODO -oUser -cConsole Main : Insert code here }

    Inst := TSomeClass.Create;
    Inst.AddToList(TInt.Create(100, 0, 101));
    Inst.AddToList(TStr.Create('Test', 10));
    Inst.Free;

  except
    on E:Exception do
    Writeln(E.Classname, ': ', E.Message);
  end;
end.

请注意,现实世界中TIntTStr的构造函数也会使用Low, High: integerLength: integer参数。我在if TObject(Element) is TInt thenelse if TObject(Element) is TStr then运行Delphi 2009时遇到了“E2089无效的类型转换”。有谁知道为什么会这样?

修改:请注意,TIntTStr只是其他10到20种类型中的两种;否则重载是该作业的工具。 :)

2 个答案:

答案 0 :(得分:7)

重新考虑你的设计。您可以使用重载而不是泛​​型类型参数,如下所示:

procedure Add (SomeString : TString); overload;
procedure Add (SomeInt : TInt); overload;

或者,如果你想使用多态,请执行Gamecat建议的操作,并将基类型作为参数传递,在该参数上使用is

procedure Add (Element : TDataType);        

Rob在对你上一个问题的评论中指出:如果你只允许两种类型并且根据实际类型有条件,那么它并不是通用的。因此,泛型可能是错误的工具。

希望有所帮助。

答案 1 :(得分:3)

问题不在于泛型。您将TDataType添加到需要TInt或TStr的列表中:

procedure TSomeClass.AddToList<T>(Element: T);
begin
  if TObject(Element) is TInt then
    FIntList.Add(TInt(Element))
  else if TObject(Element) is TStr then
    FStrList.Add(TStr(Element));
end;

解决问题。

但为什么不使用:

procedure TSomeClass.AddToList(Element: TDataType);
begin
  if Element is TInt then
    FIntList.Add(TInt(Element))
  else if Element is TStr then
    FStrList.Add(TStr(Element));
end;