使用String.Concat(Object)而非String.Concat(String)的目的是什么?

8
在C#中使用String.Concat(Object)而不是String.Concat(String)的目的是什么?为什么不直接使用Object.ToString()的隐式调用,而是传递一个可能会导致装箱的object本身呢?
Int32 i = 5;
String s = "i = ";

// Boxing happens, ToString() is called inside
Console.WriteLine(s + i);
// Why compiler doesn't call ToString() implicitly?
Console.WriteLine(s + i.ToString());

给我们以下的IL。
.method private hidebysig static void  MyDemo() cil managed
{
    // Code size       47 (0x2f)
    .maxstack  2
    .locals init ([0] int32 i, [1] string s)
    IL_0000:  nop
    IL_0001:  ldc.i4.5
    IL_0002:  stloc.0
    IL_0003:  ldstr      "i = "
    IL_0008:  stloc.1
    IL_0009:  ldloc.1
    IL_000a:  ldloc.0
    IL_000b:  box        [mscorlib]System.Int32
    IL_0010:  call       string [mscorlib]System.String::Concat(object, object)
    IL_0015:  call       void [mscorlib]System.Console::WriteLine(string)
    IL_001a:  nop
    IL_001b:  ldloc.1
    IL_001c:  ldloca.s   i
    IL_001e:  call       instance string [mscorlib]System.Int32::ToString()
    IL_0023:  call       string [mscorlib]System.String::Concat(string, string)
    IL_0028:  call       void [mscorlib]System.Console::WriteLine(string)
    IL_002d:  nop
    IL_002e:  ret
} // end of method Program::MyDemo

好问题。我想在这里补充一点:为什么没有 string Concat<T>(string s, T value) 方法,它可以被 + 运算符使用。 - Dennis
@Dennis 那有什么用处呢? - Patrick Hofman
@Dennis 编译器如何将 T valuestring s 连接起来?所有的 T 都能连接吗? - Yuval Itzchakov
在内部,只需要调用 return string.Concat(s, value.ToString()); 即可。对于值类型,这将避免装箱。 - Dennis
2个回答

3

为什么编译器要这样做呢?它无法这样做。

如果传入一个对象(在本例中是装箱的int),编译器唯一的可能性就是调用string.Concat(object, object)。它无法调用string.Concat(string, string),因为不是所有参数都是string,所以不符合第二个重载。

相反,它调用string.Concat(object, object)并在适当的情况下执行ToString

作为开发人员,您对string.Concat方法的工作原理有着熟悉的了解。编译器不知道最终它全部变成一个string

另外,如果其中一个objectnull,会发生什么?ToString将失败并引发异常。这毫无意义。只需传入object,让代码处理它。


1
编译器知道所有类型最终都继承自Object。Object包含ToString()方法。因此,当编译器遇到一个期望String的函数的非String参数时,它可能会隐式地调用ToString()。 - John Doe
1
但是作为开发人员,您对string.Concat方法的工作原理有着深入的了解。编译器并不知道最终所有内容都会变成一个字符串。 - Patrick Hofman
2
@JohnDoe - 分界线在哪里?你是说,对于任何一组重载,在其中存在两个重载的情况下,其中一个在与另一个接受string参数的相同位置上接受object参数,它应该总是调用ToString()方法来处理对象,因此object重载永远无法调用? - Damien_The_Unbeliever
确实如此。这可能适用于特定的方法(以及其他一些方法),但99%的方法并不适用。 - Patrick Hofman
2
@Damien_The_Unbeliever 我只是好奇为什么会存在对象重载,因为任何对象都可以转换为字符串。如果一个对象未初始化(NULL),那么代码可能存在问题(使用未初始化的变量),因此对象重载 1)隐藏了程序员发出空字符串的错误;2)导致不必要的装箱,降低性能和内存使用。 - John Doe

0

参考来源: http://referencesource.microsoft.com/#mscorlib/system/string.cs,8281103e6f23cb5c

揭示了:

    public static String Concat(Object arg0) {
        Contract.Ensures(Contract.Result<String>() != null);
        Contract.EndContractBlock();

        if (arg0 == null)
        {
            return String.Empty;
        }
        return arg0.ToString();
    }

它只是简单地创建了一个对象的字符串表示形式。所以您传递的任何对象都会被转换为StringString.Empty如果它为空。我认为这也使我们免于在将其转换为string之前检查“null”对象。


1
很有趣的是,有一种方法可以连接“单个事物”。 - IS4

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