Наследование Delphi-интерфейса с дженериками

в настоящее время я застрял с ошибкой компиляции, никто в нашей компании не может помочь, и я, к сожалению, не нахожу правильные шаблоны поиска для SO или google.

в качестве кода я использую 2 интерфейса, унаследованные и 2 класса, унаследованные. Следующий код воспроизводит ошибку:

program Project22;

{$APPTYPE CONSOLE}
type
  IStorageObject = interface(IInterface)
  end;
  TObjectStorage<T: IStorageObject> = class(TObject)
  end;
  IKeyStorageObject<TKey> = interface(IStorageObject)
  end;
  TKeyObjectStorage<TKey, T: IKeyStorageObject<TKey>> = class(TObjectStorage<T>)
  end;
  TImplementingClass<TKey> = class(TInterfacedObject, IKeyStorageObject<TKey>)
  end;
begin
  TKeyObjectStorage<Integer, TImplementingClass<Integer>>.Create;
end.

ошибка компилятора для "TKeyObjectStorage":

[ошибка DCC] Project22.dpr (11): e2514 тип параметр ' T ' должен поддерживать интерфейс 'IStorageObject'

Я думаю, что компилятор не распознает этот параметр t класса 'TKeyObjectStorage' правильно. Это должно быть правильно, так как разыскиваемый тип "IKeyStorageObject" имеет родительский тип IStorageObject.

почему это не работает? Что я делаю не так? Разве это невозможно в Дельфах?

1 ответов


обновление

в исходном вопросе была проблема, которую я определил (см. ниже). Однако я описываю есть штраф за XE3 и позже, но программа не компилируется в XE2 в. Таким образом, я заключаю, что это ошибка компилятора XE2 generics.

в любом случае, вот решение для Делфи XE2 в:

{$APPTYPE CONSOLE}
type
  IStorageObject = interface(IInterface)
  end;
  TObjectStorage<T: IStorageObject> = class(TObject)
  end;
  IKeyStorageObject<TKey> = interface(IStorageObject)
  end;
  TKeyObjectStorage<TKey; T: IKeyStorageObject<TKey>, IStorageObject> = class(TObjectStorage<T>)
  end;
  TImplementingClass<TKey> = class(TInterfacedObject, IStorageObject, IKeyStorageObject<TKey>)
  end;
begin
  TKeyObjectStorage<Integer, TImplementingClass<Integer>>.Create;
end.

оригинальный ответ

было бы лучше, если вы предоставил полную программу, которая показала ошибку компилятора. Вам нужно попытаться создать экземпляр объекта, чтобы увидеть эту ошибку.

но, думаю, я воспроизвел вашу проблему. Поэтому я считаю, что проблема в том, что этот код:

TKeyObjectStorage<TKey, T: IKeyStorageObject<TKey>> = ...

применяет общее ограничение к обоим TKey и T. Теперь ясно, что вы хотите, чтобы ограничение применялось только к T поэтому вам нужно написать:

TKeyObjectStorage<TKey; T: IKeyStorageObject<TKey>> = ...

вот короткая программа, которая компилирует следующий изменение в Делфи XE3 установлены:

{$APPTYPE CONSOLE}
type
  IStorageObject = interface(IInterface)
  end;
  TObjectStorage<T: IStorageObject> = class(TObject)
  end;
  IKeyStorageObject<TKey> = interface(IStorageObject)
  end;
  TKeyObjectStorage<TKey; T: IKeyStorageObject<TKey>> = class(TObjectStorage<T>)
  end;
  TImplementingClass<TKey> = class(TInterfacedObject, IKeyStorageObject<TKey>)
  end;
begin
  TKeyObjectStorage<Integer, TImplementingClass<Integer>>.Create;
end.

это довольно нюанс, изменение запятой на точку с запятой. Программирование значительными пунктуациями никогда не доставляет удовольствия. Тем не менее, вы знакомы с разницей между запятыми и полуколонами в формальных списках параметров, и поэтому не должно быть слишком большим сюрпризом увидеть то же самое различие, проведенное здесь.

на документация прикрывает это внимание:

Несколько Параметров Типа

когда вы указываете ограничения, вы отделяете несколько параметров типа по точки с запятой, как и при объявлении списка параметров:

type
  TFoo<T: ISerializable; V: IComparable>

как объявления параметров, несколько параметров типа могут быть сгруппированы вместе в списке запятых для привязки к тем же ограничениям:

type
  TFoo<S, U: ISerializable> ...

в приведенном выше примере,S и U оба связаны с ISerializable ограничение.