I doubt that you'll find any significant performance penalty to using an out
parameter. You've got to get information back to the caller somehow or other - out
is just a different way of doing it. You may find there's some penalty if you use the out parameter extensively within the method, as it may well mean an extra level of redirection for each access. However, I wouldn't expect it to be significant. As normal, write the most readable code and test whether performance is already good enough before trying to optimise further.
EDIT: The rest of this is an aside, effectively. It's only really relevant for large value types, which should usually be avoided anyway :)
I disagree with Konrad's assertion about "return values for all types > 32 bit are handled similar or identical to out arguments on the machine level anyway" though. Here's a little test app:
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
struct BigStruct
{
public Guid guid1, guid2, guid3, guid4;
public decimal dec1, dec2, dec3, dec4;
}
class Test
{
const int Iterations = 100000000;
static void Main()
{
decimal total = 0m;
// JIT first
ReturnValue();
BigStruct tmp;
OutParameter(out tmp);
Stopwatch sw = Stopwatch.StartNew();
for (int i=0; i < Iterations; i++)
{
BigStruct bs = ReturnValue();
total += bs.dec1;
}
sw.Stop();
Console.WriteLine("Using return value: {0}",
sw.ElapsedMilliseconds);
sw = Stopwatch.StartNew();
for (int i=0; i < Iterations; i++)
{
BigStruct bs;
OutParameter(out bs);
total += bs.dec1;
}
Console.WriteLine("Using out parameter: {0}",
sw.ElapsedMilliseconds);
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static BigStruct ReturnValue()
{
return new BigStruct();
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static void OutParameter(out BigStruct x)
{
x = new BigStruct();
}
}
Results:
Using return value: 11316
Using out parameter: 7461
Basically by using an out parameter we're writing the data directly to the final destination, rather than writing it to the small method's stack frame and then copying it back into the Main method's stack frame.
Feel free to criticise the benchmark app though - I may have missed something!