【问题标题】:Dealing with overloaded functions that have ambiguous parameters处理参数不明确的重载函数
【发布时间】:2012-12-19 15:23:37
【问题描述】:

以这个小示例类为例(不是我的真实代码,但它暴露了问题):

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

在您尝试使用 DoubleTDateTime 函数之前,它可以正常编译 在:

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

您将收到此编译错误:对“ToString”的模糊重载调用。 问题归结为TDateTimeDouble 的一种类型

我的问题:您如何处理此类问题?

编辑 - 我不是在为给出的示例寻找解决方案

到目前为止,我已经找到了 3 个解决方案:

  • 重命名 2 个函数之一
  • 将“Dummy”参数添加到 2 个函数之一
  • 把参数改成Var类型,缺点是不能再用常量调用这个函数

还有其他解决方案吗?

【问题讨论】:

  • 我重命名了那些 DateTime 函数
  • @CosminPrund:重命名它们是不可能的(实际上我有 30 多个重载)
  • @whosrdaddy,然后发布暴露你问题的真实代码。
  • @LURD ShowMessage( Convert.ToString( 99.99 ) ); 导致 E2251 编译器错误
  • @SirRufo,Convert.ToString( Double(Variant(99.99))) 工作。

标签: delphi delphi-xe


【解决方案1】:

重载方法可能非常有效。但是,一旦出现模棱两可的迹象,它们就会成为一种负担。 XE3 中引入的新 TStream 重载就是一个很好的例子。不难陷入编译器选择了您没想到的重载的陷阱。至少在您的代码中,编译器停止了。从这个意义上说,你是幸运的。

因此,在您的情况下,我的建议是放弃重载。在方法名称中表达不同的输入类型。是的,它有点冗长,但你不会犯任何错误,而且你的代码会编译!

【讨论】:

  • 嗯,所以没有隐藏的金蛋?真可惜:)
  • +1,完全同意。我曾经陷入这些编译器陷阱之一(在 Delphi 2006 上),我发疯了,直到我发现发生了什么
  • 这里可以使用泛型吗? TConvert.ToString<T>(value : T):string
  • @teran 这听起来很合理。我猜该实现会将值填充到 TValue 中并从那里开始。
  • 可悲的是,这似乎是最明智的做法;)
【解决方案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));

更新


要使其成为适用于所有类的通用解决方案,请考虑添加类函数来解析模糊类型。

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)));   

【讨论】:

  • 我的答案更多是关于如何为重载函数调用指定预期类型,在这些情况下,编译器无法在没有帮助的情况下解决该问题。
  • 我明白了,类型转换可能是一个解决方案,但我更喜欢重命名函数:)(+1 表示您的答案)
  • 将某些东西从整数转换为字符串、转换为日期、再转换回字符串似乎有点尴尬……
【解决方案3】:

全部折叠怎么样?:

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

【讨论】:

  • 重点不是字符串转换,而是如何处理模棱两可的重载参数。这个解决方案有一个大问题,它打开了比预期更多类型的参数可能性
  • 我的观点也不是关于字符串 ;-) 而是关于变体。你说的“比预期的类型更多”是对的,但如果它是 OP 自己的代码,他可以只支持预期的类型并使用“else”或断言其余的。
  • 我实际上是要建议这个,然后我看到了你的答案,而不是立即调用VarToStr(),你可以检查值的类型并相应地处理它。
  • PS - 评论者是 OP,而且,也许你应该在你的答案代码中演示类型检查/处理:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-18
  • 2011-06-08
  • 1970-01-01
  • 1970-01-01
  • 2021-11-02
  • 1970-01-01
相关资源
最近更新 更多