Безопасно ли генерировать дженерики в Delphi? - PullRequest
4 голосов
/ 07 декабря 2009

Мне нужно реализовать функцию, которая возвращает 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 ]

3 голосов
/ 07 декабря 2009

Нет, нет "базового класса 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 реализовать ее в следующем выпуске, но мы должны увидеть ...

0 голосов
/ 07 декабря 2009

При вызове GetMap вы уже знаете, что результатом будет TDictionary. Почему бы не создать универсальную функцию GetMap для T и U, которая возвращает TDictionary T и U?

Как это:

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

Тогда вы можете сделать это без приведения:

var
  MyMap: TMyMapType;
begin
  MyMap := GetMap<string, integer>();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...