2 Stimmen

Delphi: Generika und 'is'-Operator Problem

Auf der Grundlage einer früheren Beitrag habe ich den folgenden Code geschrieben. Bitte entschuldigen Sie die Langatmigkeit dieses Beitrags. Ich glaube, es ist besser für alle Beteiligten, den vollständigen Code zum Testen und Kommentieren zur Verfügung zu haben.

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.

Beachten Sie, dass die Konstruktoren von TInt y TStr in der realen Welt würde die Low, High: integer y Length: integer auch die Parameter. Ich habe eine "E2089 Invalid typecast" bei if TObject(Element) is TInt then y else if TObject(Element) is TStr then mit Delphi 2009. Weiß jemand, warum das passiert?

Edit: Bitte beachten Sie, dass TInt y TStr sind nur zwei von möglicherweise 10-20 anderen Typen; ansonsten ist Überladung die Werkzeug für den Job :)

7voto

jpfollenius Punkte 16148

Überdenken Sie Ihr Design. Sie können anstelle eines generischen Typparameters einfach Überladung verwenden, etwa so:

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

Oder wenn Sie Polymorphismus verwenden möchten, tun Sie, was Gamecat vorgeschlagen hat, und übergeben Sie einfach den Basistyp als Parameter, indem Sie is auf diesen Parameter:

procedure Add (Element : TDataType);        

Wie Rob in einem Kommentar zu Ihrer vorherigen Frage feststellte: Es ist nicht wirklich generisch, wenn Sie nur zwei Typen zulassen und Konditionale auf der Grundlage des aktuellen Typs haben. Generika könnten hier also das falsche Werkzeug sein.

Ich hoffe, das hilft.

3voto

Toon Krijthe Punkte 51819

Das Problem liegt nicht bei den Generika. Sie fügen einen TDataType zu einer Liste hinzu, die TInt oder TStr erwartet:

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;

Löst das Problem.

Aber warum nicht?

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;

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X