.NET Framework is a surprise box!!!
Most of the time when I need to get inspiration about how to do something, I turn to the inner bits and bolts of .NET Framework, because I think that there are a few hundred men-years worth of code there, and it does have some insights.
But, some times...
I was just looking into the
Ok, we don't have much here, and inside the .NET Framework there are lots and lots of helper classes to aggregate common functions and adhere to the D.R.Y. principle.
However, when I dove into the
The
Ok, now you're thinking that the above function could be easily rewritten as:
And perhaps the whole shebang of going through three different method calls could be avoided by simply writting:
Right?!
Well that's what I thought... Until I read the source code.
Thanks to Microsoft the source code for the .NET Framework is public, so as I always like to learn, I've downloaded the full source and installed.
When I read the source for the
After reading this I started having a little bit more respect for the guys that write this stuff.
But, some times...
I was just looking into the
Dictionary<TKey, TValue>
class when I came across this little bit of code:public virtual void GetObjectData(SerializationInfo info,
StreamingContext context)
{
if (info == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.info);
}
// ...
}
Ok, we don't have much here, and inside the .NET Framework there are lots and lots of helper classes to aggregate common functions and adhere to the D.R.Y. principle.
However, when I dove into the
ThrowArgumentNullException
method, this is what I've found:internal static void ThrowArgumentNullException(ExceptionArgument argument)
{
throw new ArgumentNullException(GetArgumentName(argument));
}
The
ExceptionArgument
type is actually an enumeration, that lists the possible values for the method argument. Well, I thought that perhaps there were more than meets the eye here, but when I went through the GetArgumentName
function... take a look:internal static string GetArgumentName(ExceptionArgument argument)
{
switch (argument)
{
case ExceptionArgument.obj:
return "obj";
case ExceptionArgument.dictionary:
return "dictionary";
case ExceptionArgument.dictionaryCreationThreshold:
return "dictionaryCreationThreshold";
case ExceptionArgument.array:
return "array";
case ExceptionArgument.info:
return "info";
case ExceptionArgument.key:
return "key";
case ExceptionArgument.collection:
return "collection";
case ExceptionArgument.list:
return "list";
case ExceptionArgument.match:
return "match";
case ExceptionArgument.converter:
return "converter";
case ExceptionArgument.queue:
return "queue";
case ExceptionArgument.stack:
return "stack";
case ExceptionArgument.capacity:
return "capacity";
case ExceptionArgument.index:
return "index";
case ExceptionArgument.startIndex:
return "startIndex";
case ExceptionArgument.value:
return "value";
case ExceptionArgument.count:
return "count";
case ExceptionArgument.arrayIndex:
return "arrayIndex";
case ExceptionArgument.name:
return "name";
case ExceptionArgument.mode:
return "mode";
}
return string.Empty;
}
Ok, now you're thinking that the above function could be easily rewritten as:
internal static string GetArgumentName(ExceptionArgument argument)
{
return argument.ToString();
}
And perhaps the whole shebang of going through three different method calls could be avoided by simply writting:
public virtual void GetObjectData(SerializationInfo info,
StreamingContext context)
{
if (info == null)
{
throw new ArgumentNullException("info");
}
// ...
}
Right?!
Well that's what I thought... Until I read the source code.
Thanks to Microsoft the source code for the .NET Framework is public, so as I always like to learn, I've downloaded the full source and installed.
When I read the source for the
ThrowHelper
class, I've come across the following explanation:The old way to throw an exception generates quite a lot
IL code and assembly code.
Following is an example:
C# source
throw new ArgumentNullException("key",
Environment.GetResourceString("ArgumentNull_Key"));
IL code:
IL_0003: ldstr "key"
IL_0008: ldstr "ArgumentNull_Key"
IL_000d: call string System.Environment::GetResourceString(string)
IL_0012: newobj instance void System.ArgumentNullException::
.ctor(string,string)
IL_0017: throw
Which is 21bytes in IL.
So we want to get rid of the ldstr and call to
Environment.GetResource in IL.
In order to do that, I created two enums: ExceptionResource,
ExceptionArgument to represent the argument name and resource
name in a small integer. The source code will be changed to
ThrowHelper.ThrowArgumentNullException
(ExceptionArgument.key,
ExceptionResource.ArgumentNull_Key);
The IL code will be 7 bytes.
IL_0008: ldc.i4.4
IL_0009: ldc.i4.4
IL_000a: call void System.ThrowHelper::
ThrowArgumentNullException
(valuetype System.ExceptionArgument)
IL_000f: ldarg.0
This will also reduce the Jitted code size a lot.
After reading this I started having a little bit more respect for the guys that write this stuff.
0 Comments:
Post a Comment