在Delphi中运行泛型是否安全?

时间:2009-12-07 09:43:12

标签: delphi generics dictionary casting

我需要实现一个返回TDictionary的函数,而不指定确切的类型。返回的值可以是TDictionary<string,Integer>TDictionary<string,string>TDictionary<string,Boolean>

我可以使用TDictionary将该函数声明为结果参数:

function GetMap: TDictionary;

然后转换返回值:

type
  TMyMapType: TDictionary<string,Integer>;
var
  MyMap: TMyMapType:
begin
...
  MyMap := GetMap as TMyMapType;
...
end;

编辑:发现似乎没有办法声明一个'泛型'结果参数类型,它与我的三种字典类型兼容。

看起来我需要像

这样的东西
type
      TMyMapType: TDictionary<string, ?>;

在Object Pascal语言中不可能(但是?)。在Java中,它将是这样的:

static Map<String, Integer>getIntegerMap() {
    Map<String, Integer> result = new TreeMap<String, Integer>() {};
    result.put("foo", Integer.valueOf(42));
    return result;        
}

static Map<String, ?> getMap() {
  return getIntegerMap();
}

public static void main(String[] args) {
    System.out.println(getMap().get("foo"));
}

2 个答案:

答案 0 :(得分:3)

不,没有“所有TDictionary版本都来自的基础TDictionary类”。参数类型是类类型的一部分。 TDictionary<T, U>的父类为TEnumerable<TPair<T, U>>,其父类为TObject

这有点烦人,但有必要保护类型安全。假设您有TDictionary<string, TMyObject>,并将其传递给期望TDictionary<string, TObject>的函数。您可能希望这可以工作,因为您可以将TMyObject传递给TObject参数。但它没有,而且有充分的理由。

编译器无法在编译时检查接收函数内部的实际类型,因此没有什么能阻止例程获取字典并调用.Add(Self.Name, Self),其中Self是TForm(或其他任何东西)和不是TMyObject。由于所有对象引用的大小都是sizeof(指针),这似乎工作得很好,但当你在代码中找回它时,它知道第二个参数应该是什么,你就遇到了一个大问题。

通过在接收函数上设置约束,有一些方法可以让Generics按照您的预期工作而不会破坏类型安全,但是Delphi目前没有实现它。 Delphi Prism确实如此,我一直试图让Delphi团队在下一个版本中实现它,但我们必须看到...

答案 1 :(得分:0)

调用GetMap时,您已经知道结果将是TDictionary。为什么不创建T和U的Generic函数GetMap,它返回T和U的TDictionary?

像这样:

function GetMap<T, U>: TDictionary<T, U>;

然后你可以不进行强制转换:

var
  MyMap: TMyMapType;
begin
  MyMap := GetMap<string, integer>();