ToString和字符串连接 – 意外行为

根据互联网的说法

String someString = "" + object1 + object2 + object3; 

在每个对象上调用ToString()

但这不会发生! 这段代码:

 String a = "a" + foo; String b = "b" + foo.ToString(); Console.WriteLine(a); Console.WriteLine(b); 

打印:

 a b("key":"foo") 

这怎么可能?

我在整个项目中对Resharper进行了全面清理,并且在某些地方破坏了代码,因为它在这样的字符串连接中删除了ToString() ! 失去了好几个小时..

编辑:这个问题发生在我正在使用的一个小型库中。 我不能提供非常短的单文件代码来重现这个但我已经用这个库创建了一个小项目并上传到github:

https://github.com/Vistritium/ToStringCSObjectConcat https://github.com/Vistritium/ToStringCSObjectConcat/blob/master/TestString/Program.cs

该图书馆长1178行。

如果您提供了将类转换为字符串的隐式运算符,则会发生这种情况,例如:

 public class Foo { public string Key { get; set; } public string Value { get; set; } public static implicit operator string(Foo foo) { return foo == null ? string.Empty : foo.Value; } public override string ToString() { var str = string.Empty; if (!string.IsNullOrEmpty(Key)) { if (str.Length > 0) str += ";"; str += ("Key=" + Key); } if (!string.IsNullOrEmpty(Value)) { if (str.Length > 0) str += ";"; str += ("Value=" + Value); } return str; } } 

在这种情况下:

  string a = "a" + new Foo { Key = "foo", Value = "" }; string b = "b" + new Foo { Key = "foo", Value = "" }.ToString(); Debug.WriteLine(a); // Prints "a". Debug.WriteLine(b); // Prints "bKey=foo 

如果你为stringFoo 重载了+运算符 ,你也可以得到这个效果。

更新

从C#语言规范, 7.2.2运算符重载 :

所有一元和二元运算符都具有在任何表达式中自动可用的预定义实现。 除了预定义的实现之外,还可以通过在类和结构中包含运算符声明来引入用户定义的实现(第10.9节) 。 用户定义的运算符实现始终优先于预定义的运算符实现:仅当不存在适用的用户定义的运算符实现时,才会考虑预定义的运算符实现。

这就是为什么自定义逻辑优先于标准逻辑调用的原因。

我刚刚做了这个,它工作得很好

 private void button1_Click(object sender, EventArgs e) { var o = new x (); string s = "ff" + o; Console.WriteLine(s); } public class x { public override string ToString() { return "This is string"; } } 

打印

ff这是字符串

这告诉我你做错了什么。 我的意思是,没有那么多你做错了,就像你期望的东西不同于你的对象在ToString产生的东西