是否有可能在Delphi中编写这个泛型?

时间:2017-01-17 20:05:35

标签: delphi generics

我有一些数据类型:

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

他们的一些例子:

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

我有一个方法,使用他们的Add方法很愉快地填充它们,直到我发现我的数据源可能有重复的键。

现在我可以在每个Add()之前用ContainsKey编写代码并做一些事情,但我认为我会很聪明:

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;

但似乎我对Delphi太聪明了。首先,在函数定义的主体中有一个强制转换,看起来它应该是不必要的,然后有一个事实,当我尝试调用AddPair时,我得到编译器错误。天真AddPair(s3, s2, FPatientTypes)让我两个

[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>'

虽然可能会更加复杂AddPair<string, TStringMap>(s3, s2, FPatientTypes)抱怨

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

是否有一些我想念的咒语,这会让Delphi脱离我想要做的事情?

2 个答案:

答案 0 :(得分:3)

D'哦。

通用中不需要两个类型参数:

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

很容易写(没有麻烦的演员阵容!)并做了它应该做的事。

答案 1 :(得分:1)

虽然这似乎是一种使用TDictionary的奇怪方式,但是获得所需内容的简单方法就是子类化。

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.