Общая запись Delphi, добавить ограничение к оператору равенства

#delphi #generics

#delphi #общие

Вопрос:

У меня есть приведенная ниже общая запись, которая переопределяет оператор равенства. Идея заключалась в том, чтобы получить некоторую проверку во время компиляции, как в примере ниже:

 TpColumn<T> = record
  class operator Equal (aLeft: TpColumn<T>; aRight: String): TRec;
  class operator Equal (aLeft: TpColumn<T>; aRight: Integer): TRec;
end;

function FormCreate;
var vStrRec: TpColumn<String>;
    vIntRec: TpColumn<Integer>;
begin
  vCond1 := vStrRec = 'hello'; // should accept
  vCond2 := vIntRec = 5;       // should accept

  vCond1 := vStrRec = 5;       // should reject, currently accepted
end;
  

Я мог бы определить TpColumnInt и TpColumnStr как отдельные типы, каждый из которых переопределяет равенство (и это работает), но я хотел бы определить массив TpColumn< T > независимо от типа T.

Невозможно использовать наследование с записями.

Невозможно определить массив, содержащий разные типы (отсюда и общие).

Невозможно переопределить операторы в классах (следовательно, записи).

Естественный вывод, к которому я пришел до сих пор, — это общие записи:

  • можно поместить TpColumn< String > и TpColumn< Integer > в один и тот же массив. РЕДАКТИРОВАТЬ: я понимаю, что я ошибся в этом предположении, думаю, тогда этот подход не сработает.
  • может перегружать операторы

Последняя часть головоломки, которую еще нужно выполнить, — это проверка во время компиляции в переопределении Equal . Где я могу добавить такое ограничение, которое решило бы эту проблему?

Я надеялся, что что-то подобное сработает, но этого не произошло:

 aLeft: TpColumn< String >; aRight: String
  

«оператор Equal должен принимать по крайней мере один тип TpColumn< T > в параметрах» — компилятор.

Достижимо ли это так, как я пытаюсь? А если нет, есть ли какой-либо другой способ добиться этого?

Комментарии:

1. Ваши операторы ошибочны. Они должны возвращать логическое значение. Общие типы различаются, даже если они созданы из одного и того же шаблона. Если вам нужен массив разных типов, вы можете создать массив нетипизированных указателей и иметь что-то в каждом указанном элементе, что позволяет различать, что это на самом деле во время выполнения. Например, первый элемент всех записей имеет один и тот же тип и представляет собой перечисление, указывающее, на что указано. Возможно, вам следует взглянуть на ORM, такие как mORMot, которые широко используют дженерики. Полный исходный код доступен бесплатно на GitHub. @arnaudbouchez

2. Для моих целей мне не нужно, чтобы они возвращали логическое значение, и эта часть работает нормально.

3. Хорошо, спасибо, я посмотрю на источники mORMot

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

5.Согласно официальной документации, operator Equal должен возвращать a Boolean .