Calling ToString() To Prevent Boxing
Asked Answered
A

1

14

With the following code snippet:

public static void Main()
{
    int v = 2;
    Console.WriteLine("number" + "," + v);
}

Apparently it's better to replace v with v.ToString() in the call to WriteLine() to prevent the value type from being boxed. However calling ToString() still allocates an object on the heap, as would boxing the value type.

So what is the benefit of using v.ToString() rather than letting it be boxed?

Update: Looks like int.ToString() is called before passing the value to string.Concat() with or without explicitly calling int.ToString() yourself. I checked the CIL for with and without ToString() and they're identical.

enter image description here

Antipas answered 18/6, 2014 at 4:47 Comment(6)
Is this just a contrived example? Because in this case, it is quite irrelevant: the time taken to output something to the console will completely overshadow any minimal performance gains you might experience by avoiding boxing.Wigwag
Still interesting. "Apparently it's better" - quotation needed. I never heard that, and I would love to know where you got that, espcecialyl the context.... I assume there is a misunderstanding here.Wrenn
Yeah this is just an example. Apparently boxing is to be avoided as it takes up memory on the heap, and means the garbage collector has to do more work. But since calling toString() also allocates an object on the heap, why or why isn't, calling toString() better than letting it be boxed?Antipas
I've read that it's better in "CLR Via C#" by Jeffrey Richter. I'll try find the page number for you if you're interested.Antipas
Boxing is allways faster than ToString(); 1. ToString result in a string which is larger on the heap than an Integer. 2. ToString needs to do the conversion to text, and in the way consult the culture and realted things. 3. boxing an int is all about allocating a small object.Jeane
but once the value type is boxed, wouldn't ToString() be called internally?Antipas
H
25

ToString() will only box a variable if its type has no override of ToString() (so it has to go to the implementation on the Object class). However, int does have an overridden ToString() (see http://msdn.microsoft.com/en-us/library/6t7dwaa5(v=vs.110).aspx), so this does not happen.

The boxing is actually performed by the + operator, because that just calls string.Concat, which expects parameters of type Object (or string, depending on which overload is used). Therefore, integers have to be boxed for the call. Then, the string.Concat method unboxes the int again and calls ToString(). Therefore, if you call it yourself, you'll save time by not having to do the boxing and unboxing.

There is a performance gain, although in most cases it will be quite marginal.

Heiser answered 18/6, 2014 at 4:59 Comment(3)
Looks like boxing never happens either way. See my updated question with a screenshot of the CIL. It calls ToString() on the int before passing it to string.Concat()Antipas
Interesting, maybe something changed in the compiler so that it's optimized, after all it's been a while since I wrote this. I know I read about this exact scenario in a book about that went pretty in depth into the C#/.NET basics, but I can't remember if I actually tested it.Heiser
the real issue is that the CSharp compiler (.NET 6 tested) emits constrained.UserQuery callvirt instance string[System.Runtime] System.Object::ToString() for normal value types whether they have ToString overriden or not. The constrianed prefix then determines what's to happen - direct call or boxing. Primitives seem special in this regardRevel

© 2022 - 2024 — McMap. All rights reserved.