Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Assign für TDictionary implementieren (https://www.delphipraxis.net/201856-assign-fuer-tdictionary-implementieren.html)

DCoderHH 4. Sep 2019 10:43

Assign für TDictionary implementieren
 
Hallo,

ich hab eine eigene Klasse (TMyDictionary), die von TDictionary abgeleitet ist erstellt. Diese soll u.a. auch eine Assign-Funktion erhalten, um das ganze Dictionary in ein anderes zu kopieren. Doch es gibt in der Zeile, die mit **FEHLER** markiert ist, diesen Fehler:

Code:
Fehler E2010 Inkompatible Typen 'MeineUnit.TValue' und 'System.Rtti.TValue'
Was kann ich tun?
(Warum klappt das Zuweisen von TKey? Das von TValue auf die gleiche Art und weise aber nicht?)

Delphi-Quellcode:
interface

TMyDictionary<TKey, TValue> = class(TDictionary<TKey, TValue>)
public
  ...
  procedure Assign(Source: TObject); virtual;
end;

...

implementation

procedure TMyDictionary<TKey, TValue>.Assign(Source: TObject);
var
  LKey: TKey;
  LValue: TValue;
begin
  if Source is TMyDictionary<TKey, TValue> then
  begin
    for LKey in (Source as TMyDictionary<TKey, TValue>).Keys do
    begin
      LValue := (Source as TMyDictionary<TKey, TValue>).Items[LKey];
      Add(LKey, LValue); <-- **FEHLER**
    end;
  end
  else
    AssignError(Source, self);
end;

Uwe Raabe 4. Sep 2019 10:56

AW: Assign für TDictionary implementieren
 
Zeig mal die zugehörigen Uses-Anweisungen. TValue ist sowohl als generischer Typ in TDictionary als auch als relater Typ in System.RTTI deklariert. Eventuell hilft es die uses-Anwwisung etwas umzubauen.

Stevie 4. Sep 2019 11:08

AW: Assign für TDictionary implementieren
 
Unabhängig vom Compilefehler: Die Signatur von Assign ist Unfug - den Source Parameter als TObject zu deklarieren ist unnötig, sowas macht nur Sinn, wenn man eine Abstrakte Basisklasse hat, wie bei TPersistent der Fall, wo erst die Ableitungen dann entscheiden, was sie annehmen - beim generischen Dictionary wohl kaum der Fall.

DCoderHH 4. Sep 2019 11:11

AW: Assign für TDictionary implementieren
 
Zitat:

Zitat von Stevie (Beitrag 1444648)
Unabhängig vom Compilefehler: Die Signatur von Assign ist Unfug - den Source Parameter als TObject zu deklarieren ist unnötig, sowas macht nur Sinn, wenn man eine Abstrakte Basisklasse hat, wie bei TPersistent der Fall, wo erst die Ableitungen dann entscheiden, was sie annehmen - beim generischen Dictionary wohl kaum der Fall.

Auch hier macht der Source Parameter als TObject Sinn, wenn man nicht nur TDictionarys zuweisen möchte...

bernau 4. Sep 2019 11:37

AW: Assign für TDictionary implementieren
 
Zitat:

Zitat von DCoderHH (Beitrag 1444649)
Zitat:

Zitat von Stevie (Beitrag 1444648)
Unabhängig vom Compilefehler: Die Signatur von Assign ist Unfug - den Source Parameter als TObject zu deklarieren ist unnötig, sowas macht nur Sinn, wenn man eine Abstrakte Basisklasse hat, wie bei TPersistent der Fall, wo erst die Ableitungen dann entscheiden, was sie annehmen - beim generischen Dictionary wohl kaum der Fall.

Auch hier macht der Source Parameter als TObject Sinn, wenn man nicht nur TDictionarys zuweisen möchte...

Aber du prüfst ja direkt, ob es TMyDictionary ist.

Delphi-Quellcode:
if Source is TMyDictionary<TKey, TValue> then


Wenn du irgend etwas anders übergibst, dann erscheint auf jeden Fall ein Fehler.

Dann lieber als Source-Parameter direkt den Type TMyDictionary verwenden. Dann fällt der Fehler direkt beim Compilieren auf.

Uwe Raabe 4. Sep 2019 11:39

AW: Assign für TDictionary implementieren
 
Zitat:

Zitat von bernau (Beitrag 1444656)
Aber du prüfst ja direkt, ob es TMyDictionary ist.

Das könnte in einer Ableitung aber ja durchaus anders sein.

bernau 4. Sep 2019 11:46

AW: Assign für TDictionary implementieren
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1444657)
Zitat:

Zitat von bernau (Beitrag 1444656)
Aber du prüfst ja direkt, ob es TMyDictionary ist.

Das könnte in einer Ableitung aber ja durchaus anders sein.

Dann dürfte in der Ableitung aber kein Inherited aufgerufen werden, da ja sofort AssignError ins Spiel kommt.

Wenn es ein ganz anderer Parameter ist, der auch das Assign vom Elternobjekt nicht verwenden darf, dann könnte man auch ein "overload" verwenden.

Schokohase 4. Sep 2019 11:56

AW: Assign für TDictionary implementieren
 
@bernau wie
Delphi-Quellcode:
inherited
darf nicht aufgerufen werden ...
Delphi-Quellcode:
procedure TMyOtherDict.Assign(Source:TObject);
begin
  if Source is TFoo then
  begin
    ...
  end
  else
    inherited;
end;
klar, nicht einfach blind aufrufen, aber durchaus konditional aufrufbar

DCoderHH 4. Sep 2019 12:06

AW: Assign für TDictionary implementieren
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1444647)
Zeig mal die zugehörigen Uses-Anweisungen. TValue ist sowohl als generischer Typ in TDictionary als auch als relater Typ in System.RTTI deklariert. Eventuell hilft es die uses-Anwwisung etwas umzubauen.

Ich hab mal alles aus der Unit gelöscht, bis das hier übrig blieb (uses Rtti in Verbindung mit TValue in Foo verursacht das Problem):

Delphi-Quellcode:
unit MyUnit;

interface

uses
 Classes, generics.defaults, generics.Collections;

type
  TTest = class(TObject)
    procedure foo;
  end;

  TMyDictionary<TKey, TValue> = class(TDictionary<TKey, TValue>)
  public
    procedure Assign(Source: TObject); virtual;
  end;

implementation

uses
  Rtti;

procedure TTest.foo;
var
  V: TValue; <-- hier kommt das TValue aus der Rtti und muss es auch!
begin
end;

procedure TMyDictionary<TKey, TValue>.Assign(Source: TObject);
var
  LKey: TKey;
  LValue: TValue;
begin
  if Source is TMyDictionary<TKey, TValue> then
  begin
    for LKey in (Source as TMyDictionary<TKey, TValue>).Keys do
    begin
      LValue := (Source as TMyDictionary<TKey, TValue>).Items[LKey];
      Add(LKey, LValue); <-- **FEHLER**
    end;
  end
end;

end.

Stevie 4. Sep 2019 12:14

AW: Assign für TDictionary implementieren
 
Der Scope auf Rtti.TValue ist näher als der auf den generischen Typparameter TValue. Also entweder umbenennen oder Rtti in das Interface uses verschieben. Diese Problematik hab ich auch schon of genug in meinem Dictionary Code gehabt.

Edit: Habs mal getestet, verschieben der unit bringt nichts. Ich würde die Klasse die das Rtti.TValue benutzt in eine andere Unit verfrachten, so dass sie nicht kollidieren - oder den generischen parameter umnennen, ich hab das mal so gelöst gehabt: map<tkey,t>

Übrigens die Schleife über die Keys und dann das Lookup jedes Wertes ist denkbar inperformant. Dann doch lieber direkt mit einer TPair<TKey,TValue> variable per for in über das Dictionary.


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:04 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz