Неявное приведение для перегруженной записи в Delphi в качестве параметра в массиве const - PullRequest
5 голосов
/ 02 сентября 2011

Мы избавились от короткой строки как часть преобразования из Delphi 7. Я хотел сделать его максимально безболезненным, поэтому мы решили, что мы можем изменить ShortString на какую-то запись, которая действовала бы таким же образом. Вот как это объявлено (это еще не все, но это основная структура, которая обрисовывает в общих чертах проблему):

TShortStringRec = record 
private
  FStuff: array [0..49] of Char;
public
  class operator Implicit(AStuff: TShortStringRec): String;
  class operator Implicit(S1: String): TShortStringRec;
end;

Это хорошо работает для установки строк в записи. Но есть функции типа format, которые принимают в качестве параметра const array of const. Есть ли способ выполнить приведение к тому, что мы хотим передать в константный массив?

function FunkyFunc : string;
var
  ssr : TShortStringRec;
begin
  ssr := 'Wall'; 
  result := format('Hello %s', [ssr]);  //<---error here
end;

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

Ответы [ 3 ]

7 голосов
/ 02 сентября 2011

Краткий ответ : Нет.
Длинный ответ : Вы спрашиваете, что компилятор каким-то образом знает, что вы хотите, чтобы изначально нетипизированный параметр был приведен к типу, который вы намереваетесь. Компилятору просто не хватает информации на сайте вызова для принятия решения. Если вы добавите оператор «Явный», а затем явным образом приведете параметр к строке, он будет работать.

2 голосов
/ 03 сентября 2011

Вы можете добавить следующее к общему объявлению:

function AsAnsiString : AnsiString;
function AsShortString : ShortString;

Затем явно использовать приведение, которое вы хотите использовать:

result := Format('hello %s',[ssr.AsAnsiString]);
1 голос
/ 15 марта 2012

Я сделал нечто очень похожее в нашей миграции с Delphi 2007, а также обнаружил, что нельзя использовать Format () для передачи записей, и после прочтения комментариев это имеет смысл.Явное приведение (в идеале к строке) сообщит компилятору, что делать;«явные» методы не требуются, однако.Что касается предложений по использованию "AsAnsiString": мне лично не нравится эта идея, потому что 1) дополнительная функция для записи, тогда как явное приведение может выполнить работу 2) если читаемость важна, то должна быть согласованность, то есть вы делаете TShortStringRec.AsAnsiString, но вам также нужно добавить явный метод для установки данных, например SetAsAnsiString (или просто сделать AsAnsiString как свойство)?Для меня это побеждает точку неявных операторов класса.Я рекомендую придерживаться явных приведений, чтобы компилятор определил, какой вызов является правильным.

Мы используем много типов string [], поэтому я автоматически сгенерировал все свои записи.Я подумал, что было бы лучше указать свойство по умолчанию, чтобы получить AnsiChars из типов ShortString, а не конвертировать их в UnicodeString, а затем получить символ через [], например:

type
 _ShortString3 = string[3]:
  ShortString3 = record
  private
    FData: _ShortString3;
    function GetAnsiChar(Index: Integer): AnsiChar;
    procedure PutAnsiChar(Index: Integer; const Value: AnsiChar);
  public
    class operator Implicit(const A: string): ShortString3;
    class operator Implicit(const A: ShortString3): string;
    class operator Equal(const A: ShortString3; B: AnsiChar): Boolean;
    class operator NotEqual(const A: ShortString3; B: AnsiChar): Boolean;
    class operator Equal(const A: ShortString3; B: ShortString3): Boolean;
    class operator NotEqual(const A: ShortString3; B: ShortString3): Boolean;
    class operator Add(const A: ShortString3; B: ShortString3): string;
    class operator Add(const A: ShortString3; B: AnsiChar): string;
    class operator Add(const A: ShortString3; B: string): string;
    property AnsiChars[Index: Integer]: AnsiChar read GetAnsiChar write PutAnsiChar; default;
end;    

FWIW - вот реализация:

{ShortString3}

function ShortString3.GetAnsiChar(Index: Integer): AnsiChar;
begin
  Result := FData[Index];
end;

procedure ShortString3.PutAnsiChar(Index: Integer; const Value: AnsiChar);
begin
  FData[Index] := Value;
end;

class operator ShortString3.Implicit(const A: string): ShortString3;
begin
  Result.FData := _ShortString3(A);
end;

class operator ShortString3.Implicit(const A: ShortString3): string;
begin
  Result := string(A.FData);
end;

class operator ShortString3.Equal(const A: ShortString3; B: AnsiChar): Boolean;
begin
  Result := A.FData = B;
end;

class operator ShortString3.NotEqual(const A: ShortString3; B: AnsiChar): Boolean;
begin
  Result := A.FData <> B;
end;

class operator ShortString3.Equal(const A: ShortString3; B: ShortString3): Boolean;
begin
  Result := A.FData = B.FData;
end;

class operator ShortString3.NotEqual(const A: ShortString3; B: ShortString3): Boolean;
begin
  Result := A.FData <> B.FData;
end;

class operator ShortString3.Add(const A: ShortString3; B: ShortString3): string;
begin
  Result := string(A.FData + B.FData);
end;

class operator ShortString3.Add(const A: ShortString3; B: AnsiChar): string;
begin
  Result := string(A.FData + B);
end;

class operator ShortString3.Add(const A: ShortString3; B: string): string;
begin
  Result := string(A.FData) + B;
end;

В целом это оказалось хорошим трюком, потому что мы вручную не возились с сотнями файлов, вместо этого просто написали 1 файл со всеминаши пользовательские записи ShortString с неявными операторами классов.(Был промежуточный шаг, который автоматически заменял все типы ShortString на наши собственные и добавлял модуль StringTypes для использования, но это было безопасно.) Исчезли тысячи предупреждений, связанных с ShortString.

...