Работа с перегруженными функциями, которые имеют неоднозначные параметры

Возьмите этот небольшой примерный класс (не мой настоящий код, но он раскрывает проблему):

Convert = class(TObject)
  public
    class function ToString(value: Double): String; overload;
    class function ToString(value: TDateTime): String; overload;
  end;

Он компилируется до тех пор, пока вы не попытаетесь использовать функции Double или TDateTime As В:

var
  d: Double;
begin
  d := 99.99;
  ShowMessage(Convert.ToString(d));

Вы получите эту ошибку компиляции: неоднозначный перегруженный вызов на "ToString". Проблема сводится к тому, что TDateTime является типом Double

Мой вопрос: как вы справляетесь с этим типом проблемы?

РЕДАКТИРОВАТЬ - я НЕ ищу решение для приведенного примера

Я нашел 3 Решения до сих пор:

  • Переименуйте одну из двух функций
  • Добавьте параметр "Dummy" к одной из двух функций
  • Измените параметры на типы Var, это имеет тот недостаток, что я больше не могу вызывать эту функцию с константами

Есть ли там какие-либо другие решения?

Ответ 1

Перегруженные методы могут быть очень эффективными. Однако, как только появляется намек на двусмысленность, они становятся ответственностью. Хорошим примером этого являются новые перегрузки TStream, введенные в XE3. Не сложно попасть в ловушку, где компилятор выбирает перегрузку, которую вы не ожидали. По крайней мере, в вашем коде компилятор остановился. В этом смысле вам повезло.

Поэтому мой совет, в вашей ситуации, состоит в том, чтобы отказаться от перегрузок. Выразите различные типы ввода в имени метода. Да, это немного более многословно, но вы не ошибетесь, и код будет скомпилирован!

Ответ 2

Ваш опубликованный пример компилируется и выполняется отлично в XE.

В комментарии вы приводите этот пример вместо:

ShowMessage( Convert.ToString( 99.99 ));  // <- gives compiler error 2251

В этом конкретном случае решение должно явно определить тип (я думал):

ShowMessage( Convert.ToString( Double(99.99) )); // <- E2089, Invalid Typecast

Взгляд в документацию:

Это сообщение об ошибке выдается для типов, не разрешенных правилами. Разрешены следующие виды бросков:

     
  •   
  • Порядковый или указательный тип к другому порядку или типу указателя  
  • Символ, строка, массив символов или pchar для строки  
  • Порядковый, действительный, строковый или вариант для варианта  
  • Вариант для порядкового, реального, строкового или варианта  
  • Ссылка на переменные для любого типа того же размера.  

Итак, чтобы явным образом сказать компилятору выбрать перегруженную функцию Double:

ShowMessage( Convert.ToString( Double(Variant(99.99)))); // Ok

Возможно, немного запутанный. Но для другой перегруженной функции это проще:

ShowMessage( Convert.ToString( EncodeDate(2013,1,5));

Update


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

Convert = Class(TObject)
  ...
  class function AsDouble( value: Double) : Double; inline; static;
  class function AsTDateTime( value: TDateTime) : TDateTime; inline; static;
end;

class function Convert.AsDouble(value: Double): Double;
begin
  Result := Value;
end;
class function Convert.AsDateTime(value: TDateTime): TDateTime;
begin
  Result := Value;
end;

Теперь вы можете вызвать свою перегруженную функцию класса с помощью констант:

ShowMessage( Convert.ToString( Convert.AsDouble(99.99)));   

Ответ 3

Как свернуть все это?:

class function Convert.ToString(value: Variant): String;
begin
   Result := VarToStr(Value);
end;