tags:

views:

152

answers:

4

what is the difference between these two statements? which is better with respect to performance?

Console.Writeline(i);
Console.Writeline(i.toString());

where i is a string or an integer.

+14  A: 

The bottom line is that writing to the console is bound to dominate the performance here - even if you're redirecting it to some sort of "null" sink.

The difference, IMO, is that

Console.WriteLine(i);

is simpler to read... so that's what I'd use until I'd proven that using the slightly-less-readable form gave a concrete benefit. In this case, neither form would end up boxing i when it's an integer, because there's an overload for WriteLine(int). A slightly more interesting question is between these two lines:

Console.WriteLine("Some format {0} stuff", i);
Console.WriteLine("Some format {0} stuff", i.ToString());

The first form will box the integer; the second won't. The difference in performance? Nothing significant.

Jon Skeet
I'd also add that your unliklely to be writing to the console within tight performance bound loops - which is ordinarily the only place that a performance difference would show up.
locster
+2  A: 

There is no practical difference, both will call ToString to convert the number to a string.

Guffa
+1  A: 

There should be no difference. The Console.WriteLine method is supposed to automaticaly calls the ToString() method if you don't explicitly do so yourself. However, if you Look at the IL code, I was surprised to see that they are not identical. Obviously, the Console.Writeline(int) must internally convert the int to a string of decimal characters, but this is not obvious from the IL...

For this code:

static void Main(string[] args)
{
    int i = 34;
    Console.WriteLine(i);
    Console.WriteLine(i.ToString());

}

The IL is

.method private hidebysig static void Main(string[] args) cil managed
{
    .entrypoint
    .maxstack 1
    .locals init (
        [0] int32 i)
    L_0000: nop 
    L_0001: ldc.i4.s 0x22
    L_0003: stloc.0 
    L_0004: ldloc.0 
    L_0005: call void [mscorlib]System.Console::WriteLine(int32)
    L_000a: nop 
    L_000b: ldloca.s i
    L_000d: call instance string [mscorlib]System.Int32::ToString()
    L_0012: call void [mscorlib]System.Console::WriteLine(string)
    L_0017: nop 
    L_0018: ret 
}

Using Jon's example, (with string.format), The first case (w/o the ToString()) the value is boxed... Code:

    int i = 34;
    Console.WriteLine(string.Format("Some format {0} stuff", i));
    Console.WriteLine(string.Format("Some format {0} stuff", i.ToString()));

the IL is

.method private hidebysig static void Main(string[] args) cil managed
{
    .entrypoint
    .maxstack 2
    .locals init (
        [0] int32 i)
    L_0000: nop 
    L_0001: ldc.i4.s 0x22
    L_0003: stloc.0 
    L_0004: ldstr "Some format {0} stuff"
    L_0009: ldloc.0 
    L_000a: box int32
    L_000f: call string [mscorlib]System.String::Format(string, object)
    L_0014: call void [mscorlib]System.Console::WriteLine(string)
    L_0019: nop 
    L_001a: ldstr "Some format {0} stuff"
    L_001f: ldloca.s i
    L_0021: call instance string [mscorlib]System.Int32::ToString()
    L_0026: call string [mscorlib]System.String::Format(string, object)
    L_002b: call void [mscorlib]System.Console::WriteLine(string)
    L_0030: nop 
    L_0031: ret 
}
Charles Bretana
There is a difference in this case if 'i' is an instance of a value type but not a .Net primitive. In that case it would box the value in order to call the WriteLine(object) override. Calling ToString() on a value type directly shouldn't cause a box IIRC
JaredPar
@JaredPar - No boxing will occur as long as the value type overrides `Object.ToString`.
Andrew Hare
I did the test, and edited my answer... look at IL... no boxing takes place, and, surprisingly, no explicit call to ToString() takes place either..
Charles Bretana
Of course they are not identical, you are calling two different methods. They both end up calling ToString with the same settings, but they don't do it in the exact same way.
Guffa
@Guffa, (because you use the phrase 'of course'), in the first case, you are calling the same method (`WriteLine()`). It was not unreasonable to suspect that the compiler might translate that into a call to ToString(), as if you had called it yourself... (the C# compiler does many other such syntactical translations for you already) in which case the IL would be identical...
Charles Bretana
@Charles: The overloaded methods have the same name, but at the level we are discussing this (e.g. posting IL disassembly) it should already be clear to everyone that it's not the same method that is called.
Guffa
@Guffa, true, that's what it turned out to actually be, but that is not obvious from the syntax. The underlying method could just as easily have been `Console.WriteLine(object)` and that single method could have called ToString() on whatever object was passed in whenever the object was itself not a string... So without knowing how WriteLine() is implemented, what overloads exist, or what the arguments are typed as, it is not "clear to everyone" ... `String.Format(string, object)` is indeed a case where exactly the opposite is true.
Charles Bretana
A: 

First off, optimizing to this level is really not going to get you any benefits. Optimize your algorithms, then profile, and optimize your bottlenecks. I'd focus on which is more readable and maintainable (in which I prefer the first, in both cases...)

However, from a performance standpoint, the first will typically be better. If you call the first with an int, it effectively calls the second. With a string, you get an extra (no-op) method call.

Reed Copsey