Visual Studio 2010 SP1: DebuggerTypeProxy works again! *yay*

A while ago I bumped into a bug in Visual Studio 2010 + Silverlight 4.

While working with a List / Dictionary / … it didn’t show the items in the list, instead it showed the normal ‘raw view’:

No debug view

As you can see, there was no view to see the items.

What you would expect to see is this:

DebugView!

I reported the bug (many others did too!). The problem was that it was fixed in SL3, but not ported to SL4.

Now it’s fixed! This makes my work a lot easier. When we get SP1 @ work too that is!

Cheers!

.NET natural sort, a possible solution.

You have a list of items, let’s say 20 elements, starting at 1, until 20 (inclusive). We shuffle the list and we try to sort it.

  1. List<string> normalDotNetSort = GiveMeANewList();

The code to create the list:

  1. private static List<string> GiveMeANewList()
  2. {
  3.     List<string> list = new List<string>();
  4.  
  5.     for (int i = 1; i <= 20; i++)
  6.     {
  7.         list.Add(string.Format("{0}", i));
  8.     }
  9.  
  10.     return list.MixList();
  11. }

MixList just shuffles the list.

We’re using a normal Generic List and to sort, let’s use the Sort method, and write it to the console:

  1. normalDotNetSort.Sort();
  2. normalDotNetSort.ForEach(Console.WriteLine);

What would be the result?

.

.

.

.

.

.

.

.

.

.

.

.

.

1
10
11
12
13
14
15
16
17
18
19
2
20
3
4
5
6
7
8
9

That’s not what we wanted, but it is what we told the code to do. It first sorts on the first character, and then on the second (and so on…). That’s why 19 takes precedence of 2, since 1 < 2.

How do we fix this?

There is a little gem in the shlwapi.dll, namely StrCmpLogicalW. Since this is a native function we need to do a DllImport to expose the function to our C# code:

  1. public static class SafeNativeMethods
  2. {
  3.     [DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
  4.     public static extern int StrCmpLogicalW(string psz1, string psz2);
  5. }

Now we can use this function in our own string comparer:

  1. public sealed class NaturalStringComparer : IComparer<string>
  2. {
  3.     #region IComparer<string> Members
  4.  
  5.     public int Compare(string x, string y)
  6.     {
  7.         return SafeNativeMethods.StrCmpLogicalW(x, y);
  8.     }
  9.  
  10.     #endregion
  11. }

And use this comparer to sort our list:

  1. List<string> interopSort = GiveMeANewList();
  2. interopSort.Sort(new NaturalStringComparer());
  3. interopSort.ForEach(Console.WriteLine);

And the result:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

Much better no?

Dictionary<TKey, TValue> finding key: try/catch vs TryGetValue

Today I saw some code where the developer accessed a dictionary like this:

  1. void Foo(int keyToFindInDictionary)
  2. {
  3.     Dictionary<int, string> dictionary = new Dictionary<int, string>();
  4.  
  5.     try
  6.     {
  7.         DoSomethingWithTheResult(dictionary[keyToFindInDictionary]);
  8.     }
  9.     catch (KeyNotFoundException)
  10.     {
  11.         // fallback
  12.     }
  13. }
  14.  
  15. private void DoSomethingWithTheResult(string s)
  16. {
  17.     // do something
  18. }

As you can see he catches the exception to handle the fact that the given key was not found in the dictionary.

I told him that there was a better way, i.e. Dictionary<TKey, TValue>.TryGetValue.

And then the curious part of me started thinking, how much better is it? Is it faster? Slower?

So I wrote the following small piece of code to test my statement that TryGetValue is better than catching the KeyNotFoundException.

  1. namespace DictionaryTryGetValueVersusException
  2. {
  3.     using System;
  4.     using System.Collections.Generic;
  5.     using System.Diagnostics;
  6.  
  7.     internal class Program
  8.     {
  9.         private static void Main()
  10.         {
  11.             // create a dictionary with some values
  12.             Dictionary<string, string> dictionary = new Dictionary<string, string>();
  13.  
  14.             // add 10,000 items
  15.             for (int i = 0; i < 10000; i++)
  16.             {
  17.                 if (i == 5000)
  18.                 {
  19.                     // skip
  20.                     continue;
  21.                 }
  22.  
  23.                 dictionary.Add(string.Format("Key{0}", i), string.Format("Value{0}", i));
  24.             }
  25.  
  26.             Stopwatch stopwatch = new Stopwatch();
  27.  
  28.             stopwatch.Start();
  29.  
  30.             const string keyToFindInDictionary = "Key5000";
  31.  
  32.             for (int i = 0; i < 10000; i++)
  33.             {
  34.                 // 5000 does not exist
  35.                 try
  36.                 {
  37.                     // execute a method on the variable, so that he compiler doesn't optimize it.
  38.                     dictionary[keyToFindInDictionary];
  39.                 }
  40.                 catch (Exception)
  41.                 {
  42.                     // ignore
  43.                 }
  44.             }
  45.  
  46.             stopwatch.Stop();
  47.             Console.WriteLine("Dictionary lookup with try/catch took: {0}", stopwatch.ElapsedTicks);
  48.  
  49.             stopwatch.Restart();
  50.  
  51.             for (int i = 0; i < 10000; i++)
  52.             {
  53.                 string notFound;
  54.                 // 5000 does not exist
  55.                 dictionary.TryGetValue(keyToFindInDictionary, out notFound);
  56.             }
  57.  
  58.             stopwatch.Stop();
  59.             Console.WriteLine("Dictionary lookup with TryGetValue took: {0}", stopwatch.ElapsedTicks);
  60.  
  61.             Console.WriteLine("Done, press enter to exit");
  62.             Console.ReadLine();
  63.         }
  64.     }
  65. }

As you can see we add 10,000 items to the dictionary, skipping the 5000th item, and then we do a lookup in the dictionary, 10,000 times, on the key that doesn’t exist, to measure the performance difference between the 2 previously discussed methods.

To run this test I did a Release Build in Visual Studio 2010, .NET 4.0, Any CPU, and this is the result:

Results

Dictionary lookup with try/catch took: 1069625
Dictionary lookup with TryGetValue took: 864
Done, press enter to exit

As you can see there is a HUGE difference. The TryGetValue-way was about 1237 faster!

Exception throwing is very heavy! Don’t forget that. It doesn’t mean that you need to program without exceptions, but when you EXPECT that a Key is not present in a given dictionary, don’t use the exception. Use the TryGetValue. If you always expect it to be there then it’s normal to catch the exception, because it’s exceptional that the key was not found.

PS: I tried the code again by skipping the 9999th item, and the results were about the same, take or leave a few milliseconds. So searching in the dictionary is very performant (close to O(1), as written in the Remarks section on this page.)