I've discovered that the following code:
public static class MimeHelper
{
public static string GetMimeType(string strFileName)
{
string retval;
switch (System.IO.Path.GetExtension(strFileName).ToLower())
{
case ".3dm": retval = "x-world/x-3dmf"; break;
case ".3dmf": retval = "x-world/x-3dmf"; break;
case ".a": retval = "application/octet-stream"; break;
// etc...
default: retval = "application/octet-stream"; break;
}
return retval;
}
}
causes the compiler to create this namespaceless, internal class (copied from Reflector):
<PrivateImplementationDetails>{621DEE27-4B15-4773-9203-D6658527CF2B}
- $$method0x60000b0-1 : Dictionary<String, Int32>
- Used By: MimeHelper.GetMimeType(String) : String
Why is that? How would I change the above code so it doesn't happen (just out of interest)
Thanks
Andrew
-
It's creating the dictionary to handle the lookups of the various cases in the switch statement instead of making several branching ifs out of it to set the return value. Trust me -- you don't want to change how it's doing it -- unless you want to make the map explicit.
ASIDE: I had originally assumed that the dictionary stored a map from each case to the an index into another map for the return values. According to @Scott (see comments), it actually stores an index to a label for the code that should be executed for that case. This makes absolute sense when you consider that the code that would be executed for each case may differ and may be much longer than in the given example.
EDIT: Based on your comment, I think I might be tempted to store the mappings in an external configuration file, read them in during start up, and construct the actual map -- either a single level map from key to value or a similar multilevel map from key to index and index to value. I think it would be easier to maintain these mappings in a configuration file than to update the code every time you needed to add or remove a particular case.
Andrew Hare : I thought that as well but when I compiled the type locally (both debug and release) I didn't see any compiler generated stuff.tvanfosson : Different version of the compiler? Different context?tvanfosson : Or perhaps you didn't include as much in the code replaced by the ellipsis and it didn't kick off the need for optimizing it?Andrew Hare : Must be - nicely done. +1Andrew Bullock : probably because in my version there's like 457 case statements, it probably doesnt optimise it in such a small case as provided aboveScott Wisniewski : You are correct that the integers are indexes. However, they are not return value indexes. Instead they are indexes into an array of labels. The JIT compiler uses the array of labels and the int value returned from the integer to quickly jump to the appropriate case label without having to do a bunch of comparisons.tvanfosson : Yeah that makes more sense in the general case since it would need to apply regardless of what the code block is doing. I removed the incorrect aside and will update. -
See this, for example.
-
What is happening is compiler is creating an internal class that it emits at compile time. This class is called
<PrivateImplementationDetails>{99999999-9999-9999-9999-999999999999}, the GUID component of this class is generated at compile time so it changes with every build. Internally in this class there is a dictionary that contains the different case variables, and an int corresponding to each value. It then replaces the switch statement with a lookup in the dictionary to get the corresponding int, and does a switch on the int value (much more efficient than doing a bunch of sting compares).
0 comments:
Post a Comment