Consider this code:
static void FillUsingAsNullable()
{
int?[] arr = new int?[1 << 24];
var sw = System.Diagnostics.Stopwatch.StartNew();
for (int i = 0; i < arr.Length; ++i)
arr[i] = GetObject() as int?;
Console.WriteLine("{0:N0}", sw.ElapsedTicks);
}
static void FillUsingOwnCode()
{
int?[] arr = new int?[1 << 24];
var sw = System.Diagnostics.Stopwatch.StartNew();
for (int i = 0; i < arr.Length; ++i)
{
object temporary = GetObject();
arr[i] = temporary is int ? (int?)temporary : null;
}
Console.WriteLine("{0:N0}", sw.ElapsedTicks);
}
static object GetObject()
{
//Uncomment only one:
//return new object();
//return 42;
//return null;
}
As far as I can see, the methods FillUsingAsNullable
and FillUsingOwnCode
should be equivalent.
But it looks like the "own code" version is clearly faster.
There are 2
choices for compiling "x86" or "x64", and 2
choices for compiling "Debug" or "Release (optimizations)", and 3
choices for what to return in GetObject
method. As far as I can see, in all of these 2*2*3 == 12
cases, the "own code" version is significantly faster than the "as nullable" version.
The question: Is as
with Nullable<>
unnecessarily slow, or am I missing something here (quite likely)?
Related thread: Performance surprise with “as” and nullable types.
I think your test results are being dominated by measurement error.
Here is my program:
Here is what I get running in Release, outside debugger, with
return 42
:Note that there is a pretty wide variance between runs. You would probably need to run several more times in series to get good a good metric for performance.
Here is what happens when we change
GetObject()
to return(int?)42
.And again, with the same configuration:
If you really want to gather meaningful data, I suggest repeating the two tests in different orders, several times over and looking at the result mean and standard deviation.
I suspect the biggest time sink in these methods is memory cache invalidation, so the result for a given test is probably determined by where exactly the array winds up allocated for each test and when GC happens to kick in during the frequent boxing allocations.