如何在Delphi对象或字符串中隐式使用ToString()方法?

4

Delphi就像英国皇家卫队一样,它不喜欢模棱两可的代码,甚至会为了保护硬编码而拒绝修改。但Java就像一个街头女子,当我在Java中使用以下代码时:

 Button button = new Button();
 String a = "This is a " + button;

我收到了这是一个按钮

但如果我在Delphi中这样做:

 ShowMessage('This is a ' + Button1);

我遇到了一个错误,因为Delphi现在有toString()方法,但是它不会隐式地调用它。因为OP中的字面字符串不是对象。正确的使用方式如下:

 ShowMessage('This is a ' + Button1.toString());

有没有办法覆盖这种行为,使它像Java那样工作?
参考链接:对象如何隐式调用toString方法?

9
不确定我应该给你+1还是-1,因为你称Java为妓女。 - MK.
1
Java中的默认toString()实现不会给出对象(变量)名称,它将返回类似于someObjectClassname@hashcodenumber的内容-请参见https://dev59.com/TW445IYBdhLWcg3wwc2g。 - mjn
1
请注意,在Java中,此功能不仅限于对象。自Java的第一个版本以来,字符串连接也适用于基本类型。 - mjn
@MK 这就是为什么每个人都想要“她”;-) - NaN
1
我认为你可以尝试使用一些带有隐式类型转换的接口或记录。然后它会像这样进行:IMyString := 'This is a '; IMyString := IMyString + Button1; - Arioch 'The
显示剩余12条评论
3个回答

6

无法对对象实例执行隐式转换或方法调用。

如果这是您控制的记录,则可以实现一个Implicit类操作符,该操作符将执行到string的转换。

您所提到的讨论链接只是关于PrintStream.println()的实现细节。它依赖于String.valueOf()来为任何对象提供字符串表示形式,而String.valueOf()本身则依赖于Object.toString()。事实上,有关println()的讨论与Java中+运算符的工作方式无关,这是您问题的关键问题。

Delphi的TObject具有虚拟的ToString方法,可用于执行相同的目的。因此,在Delphi代码中使用与PrintStream.println()完全相同的技术将变得很容易。


你能否举个隐式类操作符的例子来丰富你的回答呢? ;-} - NaN
1
抱歉,你指的是什么样的例子? - David Heffernan
你是否知道哪个(非.Net)版本的Delphi引入了TObject.ToString - Rob Kennedy
@Rob 根据Marco的说法,这是D2009:http://blog.marcocantu.com/blog/6hidden_delphi2009.html - David Heffernan

4
如果您有一个类似于“格式”(Format)的特殊函数,就可以获得该行为。几年前,当内置函数不支持Unicode时,我编写了这样一个函数。现在,我已经更新了它,以支持在将对象作为%s格式字符串的参数传递时,调用ToString。您可以像这样调用它:
ShowMessage(WideFormat('This is a %s', [Button1]));

很抱歉,这份代码已经好几年没有更新了,因此在新版的 Delphi 中可能不能直接使用。您需要自行决定是否值得花时间去更新这个代码,不过它曾经被加入到 Project Jedi 中,并且也稍作更新以支持 UnicodeString 和 64 位编译。


谢谢。不过,我现在无法保证它的质量,因为我拥有的最后一个 Delphi 版本是 Delphi 2005。有人应该更新代码以考虑 UnicodeString 作为本机数据类型而不仅仅是参数类型,但我不确定我是否是那个人。不过,所有代码都在 GitHub 上,所以任何感兴趣的人都可以 fork 它或向我发送 pull 请求。 - Rob Kennedy
我赞同 @EASI,这段代码非常好读 :) 但是等等,你最后使用的 Delphi 版本是 Delphi 2005...这是否意味着你不再使用 Delphi/Pascal 编程了? :( - Wodzu
我自2007年以来就没有再使用Delphi了,@Wodzu(除了上周末花几分钟时间帮助我父亲调试Delphi 5中的一个挂起程序)。我自2005年以来就没有再专业地使用Delphi了。 - Rob Kennedy
不是很准确,@David。在开发过程中,我有一个测试项目。主要只调用一次函数,然后为每个需要测试的情况更改参数列表。这是近10年前的事了;当时我从未听说过单元测试。 - Rob Kennedy
这使得移植到 Unicode Delphi 不太吸引人。 - David Heffernan

2

很遗憾,它只适用于ARM编译器和Delphi.NET。Nick Hodges在http://edn.embarcadero.com/article/34324上撰写了一篇很棒的文章。

TMyClass = class
    class operator Add(a, b: TMyClass): TMyClass; // Addition of two operands of type TMyClass
    class operator Subtract(a, b: TMyClass): TMyclass; // Subtraction of type TMyClass
    class operator Implicit(a: Integer): TMyClass; // Implicit conversion of an Integer to type TMyClass
    class operator Implicit(a: TMyClass): Integer; // Implicit conversion of TMyClass to Integer
    class operator Explicit(a: Double): TMyClass; // Explicit conversion of a Double to TMyClass
end;

// Example implementation of Add class operator 
TMyClass.Add(a, b: TMyClass): TMyClass;
begin
  ...
end;

var
x, y: TMyClass
begin
  x := 12; // Implicit conversion from an Integer 
  y := x + x; // Calls TMyClass.Add(a, b: TMyClass): TMyClass 
  b := b + 100; // Calls TMyClass.Add(b, TMyClass.Implicit(100)) 
end;

1
此外,它只适用于Delphi.net和新的移动编译器。对于桌面版Delphi编译器,运算符重载仅适用于记录。 - David Heffernan
4
向未来的读者问候,如果现在是2015年,那么这可能是最好的答案。 - Wouter van Nifterick

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接