Wednesday, July 30, 2008

Great series of Separation of Concern by Jimmy Bogard

I just finished reading Jimmy Bogard's 5 series of Separation of Concern by example and they are just too awesome to be missed out.

The series :
# Separation of Concerns - how not to do it
# Separation of Concerns by example: Part 1 - Refactoring away from static class
# Separation of Concerns by example: Part 2 - Specialized interface for Cache
# Separation of Concerns by example: Part 3 - Creating the repository
# Separation of Concerns by example: Part 4 - Fixing a bug with unit test
# Separation of Concerns by example: Part 5 - Dependency Injection with StructureMap

The best thing that I like about them is that they are based on a real world example :D
Enuf said, go and see for your self ;)

Monday, July 28, 2008

C# 2.0 Generic Collection Sort By Value

I’m working on a web application prototype and I’m using some dummy data in xml form because it is simple and I don’t want to care about the database for a prototype ;)

Let say this is my sample data :

<root>
    <member id="1" name="Jeff" />
    <member id="2" name="Fred" />
    <member id="3" name="Greg" />
    <member id="4" name="Andy" />
</root>

I have some drop down lists or combo boxes to fill in with this kind of data in the form, and I want them to be sorted based on the description (name) not based on the key (id).

Since the data come from xml file, it may not be sorted that way, so I need to find a way to sort the data first and then bind the values to the drop down lists.

Firstly I thought it will be very simple, only need to create a class which implements IComparer for this and use it in the available generic collection types. However, it only true at the new IComparer class, but not on the generic collection part, I found out that SortedDictionary<TKey, TValue> and SortedList<TKey, TValue> will use the key to sort, even though we can specify the IComparer in the constructor.

So based on the forum discussion, I found that we can use a generic List<T> to perform sorting and we can use KeyValuePair<TKey, TValue>as the type of T.

Here is the SortByValueComparer class which implements IComparer :

public class SortByValueComparer<TKey, TValue> : IComparer<KeyValuePair<TKey, TValue>>
{
    #region IComparer<KeyValuePair<TKey, TValue>> Members

    public int Compare(KeyValuePair<TKey, TValue> x, KeyValuePair<TKey, TValue> y)
    {
        return Comparer<TValue>.Default.Compare(x.Value, y.Value);
    }

    #endregion
}

Then we can use List<T> such as :

[Fact]
public void Test_ListSort()
{
    List<KeyValuePair<string, string>> l = new List<KeyValuePair<string, string>>();
    l.Add(new KeyValuePair<string, string>("1", "Jeff"));
    l.Add(new KeyValuePair<string, string>("2", "Fred"));
    l.Add(new KeyValuePair<string, string>("3", "Greg"));
    l.Add(new KeyValuePair<string, string>("4", "Andy"));

    Assert.Equal(l[0].Value, "Jeff");
    Assert.Equal(l[1].Value, "Fred");
    Assert.Equal(l[2].Value, "Greg");
    Assert.Equal(l[3].Value, "Andy");

    // Sort the collection based on the value
    l.Sort(new SortByValueComparer<string, string>());

    Assert.Equal(l[0].Value, "Andy");
    Assert.Equal(l[1].Value, "Fred");
    Assert.Equal(l[2].Value, "Greg");
    Assert.Equal(l[3].Value, "Jeff");
}

However, I felt that the code is a bit cluttered, so I add a new Custom List class which implements List<T> :

public class CustomList<TKey, TValue> : List<KeyValuePair<TKey, TValue>>
{
    public CustomList() : base() { }
    public CustomList(int capacity) : base(capacity) { }

    public void AddEntry(TKey key, TValue value)
    {
        this.Add(new KeyValuePair<TKey, TValue>(key, value));
    }

    public void SortByValue()
    {
        this.Sort(new SortByValueComparer<TKey, TValue>());
    }
}

So I can use it like this :

[Fact]
public void Test_CustomList()
{
    CustomList<string, string> l = new CustomList<string, string>();
    l.AddEntry("1", "Jeff");
    l.AddEntry("2", "Fred");
    l.AddEntry("3", "Greg");
    l.AddEntry("4", "Andy");

    Assert.Equal(l[0].Value, "Jeff");
    Assert.Equal(l[1].Value, "Fred");
    Assert.Equal(l[2].Value, "Greg");
    Assert.Equal(l[3].Value, "Andy");

    // Sort the collection based on the value
    l.SortByValue();

    Assert.Equal(l[0].Value, "Andy");
    Assert.Equal(l[1].Value, "Fred");
    Assert.Equal(l[2].Value, "Greg");
    Assert.Equal(l[3].Value, "Jeff");
}

Hope this helps ;)