2017-01-17 6 views
0

Ich habe einige Datentypen:Ist es möglich, dieses generische in Delphi zu schreiben?

type 
    TICD10CodeMap = TObjectDictionary<string, TICD10LookupResult>; 
    TStringMap = TDictionary<string, string>; 
    TFMRecMap = TDictionary<string, TFilemanRecord>; 

Und einige Beispiele davon:

var 
    FICD10Codes: TICD10CodeMap; 
    FPatientTypes: TStringMap; 
    FPOVs: TFMRecMap; 
    FTreatmentTypes: TStringMap; 
    FTypesOfCare: TStringMap; 

Und ich hatte eine Methode, die sie glücklich war bevölkern, ihre Methoden hinzufügen verwenden, bis ich, dass meine Daten entdeckt Quelle könnte doppelte Schlüssel enthalten.

Jetzt konnte ich nur schreiben Code mit ContainsKey vor jedem Add() und etwas tun, aber ich dachte, dass ich klug wäre:

procedure AddPair<ValType, DictType: TDictionary<string, ValType>> 
    (Key: string; Val: ValType; 
    Dict: DictType); 
begin 
    if (Dict as TDictionary<string, ValType>).ContainsKey(Key) then 
    AddPair('Copy of ' + Key, Val, Dict) 
    else 
    Dict.Add(Key, Val); 
end; 

Aber es scheint, dass ich für Delphi zu klug bin. Zunächst einmal gibt es die Besetzung in dem Körper der Funktionsdefinition, die sollte wie es scheint nicht notwendig sein, dann gibt es die Tatsache, dass, wenn ich versuche AddPair zu nennen, ich Compiler-Fehler erhalten. Die naive AddPair(s3, s2, FPatientTypes) wird mir beide

[dcc32 Error] uReverseVistaLookups.pas(116): E2010 Incompatible types: 'ValType' and 'string' 
[dcc32 Error] uReverseVistaLookups.pas(116): E2010 Incompatible types: 'DictType' and 'System.Generics.Collections.TDictionary<System.string,System.string>' 

während die Möchtegern-mehr-sophisticated AddPair<string, TStringMap>(s3, s2, FPatientTypes) beschwert sich über

[dcc32 Error] uReverseVistaLookups.pas(127): E2515 Type parameter 'ValType' is not compatible with type 'System.Generics.Collections.TDictionary<System.string,System.string>' 

Gibt es eine Beschwörung, die ich fehle, die Delphi machen würde von dem, was ich versuche ich hier zu machen?

+0

Dies scheint nicht eine generische Methode zu müssen. Sie haben die generischen Typen bereits instanziiert. Verwenden Sie die Typaliase, die Sie im ersten Codeblock der Frage deklarieren. –

+0

@DavidHeffernan nein, ich will eine einzige Kennung haben, mit dem ich alle Anrufe an die Add-Methoden der verschiedenen Container ersetzen kann. Ich habe mir selbst geantwortet, siehe unten. – wades

+0

Warum haben Sie diese Typen deklariert? –

Antwort

3

D'oh.

Es besteht keine Notwendigkeit für zwei Typ-Parameter im generic: (! Ohne die lästige Besetzung)

procedure AddPair<ValType>(Key: string; Val: ValType; 
    Dict: TDictionary<string, ValType>); 

ist einfach zu schreiben und das tut, was es soll.

+0

Persönlich würde ich es als Klassenhelfer stattdessen tun, eine Art "neue" Methode hinzufügen, um die 'TDictionary ' Klasse selbst. Wenn ich wirklich das Verhalten "zweiten Wert ignorieren" brauche. Sonst würde ich nur Readymade Lager 'TDictionary .AddOrSetValue' Methode verwenden –

+0

Nein, AddPair ist eine Methode auf die Sache, die die Wörterbücher enthält. – wades

1

Während dies scheint eine seltsame Möglichkeit, eine TDictionary zu verwenden, ist eine einfache Möglichkeit zu bekommen, was Sie wollen, ist einfach Unterklasse.

program Project1; 
{$APPTYPE CONSOLE} 
uses 
    Generics.Collections, SysUtils; 

type 
    TCopyKeyMap<TValue> = class(TDictionary<string, TValue>) 
    public 
     procedure AddWithCopy(const Key: string; const Value: TValue); 
    end; 
    TStringMap = TCopyKeyMap<string>; 

procedure TCopyKeyMap<TValue>.AddWithCopy(const Key: string; const Value: TValue); 
begin 
    if ContainsKey(Key) then 
    AddWithCopy('Copy of ' + Key, Value) 
    else 
    Add(Key, Value); 
end; 

var 
    sm : TStringMap; 
    sp : TPair<string, string>; 
begin 
    sm := TStringMap.Create; 
    try 
    sm.AddWithCopy('foo', 'bar'); 
    sm.AddWithCopy('foo', 'bat'); 
    sm.AddWithCopy('foo', 'bam'); 
    for sp in sm do WriteLn(Format('%s : %s', [sp.Key,sp.Value])); 
    finally 
    sm.Free; 
    end; 
    ReadLn; 
end. 
+0

Unterklasse .... oder einen Klassenhelfer :-D –

+0

Auch ich glaube, while-Schleife wäre hier besser als Rekursion, obwohl es eine Frage des Geschmacks ist, praktisch. –

+1

@ Arioch'Das Es ist eine alberne Idee, um damit zu beginnen, um ehrlich zu sein. Die praktische Handhabung eines Datasets mit einer Menge lächerlicher quasi-doppelter Schlüssel wird lange vor der Rekursion zu einem Problem werden. –

Verwandte Themen