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.
- List<string> normalDotNetSort = GiveMeANewList();
The code to create the list:
- private static List<string> GiveMeANewList()
- {
- List<string> list = new List<string>();
- for (int i = 1; i <= 20; i++)
- {
- list.Add(string.Format("{0}", i));
- }
- return list.MixList();
- }
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:
- normalDotNetSort.Sort();
- 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:
- public static class SafeNativeMethods
- {
- [DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
- public static extern int StrCmpLogicalW(string psz1, string psz2);
- }
Now we can use this function in our own string comparer:
- public sealed class NaturalStringComparer : IComparer<string>
- {
- #region IComparer<string> Members
- public int Compare(string x, string y)
- {
- return SafeNativeMethods.StrCmpLogicalW(x, y);
- }
- #endregion
- }
And use this comparer to sort our list:
- List<string> interopSort = GiveMeANewList();
- interopSort.Sort(new NaturalStringComparer());
- 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?