C# Generics Annoyance
Let my start by saying this is not a huge Annoyance. This is more of a “winy girl who didn’t get to go to Miami” annoyance. There is a perfectly good solution to this, it just isn’t the solution with the syntax that I want. That, and I feel like wining. The crux of the issue is that I can’t write a generic property the way I can write a generic method.
Anyway, I’ve been writing a lot of data bound web sites these days. As such, you end up having to resolve the same problems over and over and over again. One such problem is how to load a drop down list control generically, and simply. This is not a complicated control, but it is still possible to make mistakes.
One of the other reasons this comes up a lot is because I use the MVP pattern when creating my web applications. Something I’ve found when writing my view: don’t care about what type the data is if you don’t have to. I think this is related to something called “duck typing”, but I’m too lazy to look it up and make sure right now. Pretty sure it is a Ruby thing — but those guys are just crazy anyway.
A prime example of this has to do with the drop down list. I can pass it a DataSet, an IEnumerable, or a generic list of whatever data I want. It has these two wonderful properties: DataTextField and DataValueField that determine what is displayed and what is returned by the control. It works great — but this should be a great example of not having to care about what I’m passing it. The presenter needs to care, but the view should give two hoots what goes in there.
So to help solve this problem I created a new generic class called NameValue. The basics of the control are this: you can define a Name and a Value. You can also send it a list of a single value, if you want, but you still get the Name/Value pair their to play with.
If you are still in the dark ages (like me most of the time) and still writing your code with C# 2.0 (.Net 2.), the class will look like this:
[Serializable] public class NameValue<N,V> { private N _name; private V _value; public NameValue() { } public NameValue(N name, V value) { _name = name; _value = value; } public N Name { get { return _name; } set { _name = value; } } public V Value { get { return _value; } set { _value = value; } } }
If you are using C# 3.0 (and thereby forcing me to hate you), the class will look like this:
[Serializable] public class NameValue<N,V> { public N Name {get;set; } public V Value { get; set; } public NameValue() { } public NameValue(N name, V value) { Name = name; Value = value; } }
The next step, in the presenter, is to load a Generic list with a bunch of data in this class. For argument sake we will say it looks like this:
public List<NameValue<string, string>> GetListOfData() { List<NameValue<string, string>> list = new List<NameValue<string, string>>(); list.Add(new NameValue<string, string>("Hi there", "1")); list.Add(new NameValue<string, string>("Hi there2", "2")); list.Add(new NameValue<string, string>("Hi there3", "3")); list.Add(new NameValue<string, string>("Hi there4", "4")); return list; }
Again, if you are using C# 3.0, and I hate you for that, you could change the first line of code to look like this:
var list = new List<NameValue<string, string>>();
Then you can set the properties by name like this:
list.Add(new NameValue<string, string> { Name = "Hi there-1", Value = "1" });
But really, is it really that better? (Actually, I think it is. But I’m not going to say that until I’m using it full time. Until then, all of you using C# 3.0 still suck).
OK, now here comes the really whiny part. I want to hand this data to a drop down list (a combo box for windows developers). All the drop down list needs to know is there there is a name and a value in the object. It can even know that it is being handed a generic list of NameValue objects. I just don’t want to have to specify what the types of the name and value are.
Normally when I’m handing data to a view, I give the data through properties. So, for my previous example I could code a property into my view interface like this:
List<NameValue<string, string>> ComboBoxData { set; }
But there is that <string, string> part in there. What if I have to change the date type to an int and a double at the last minute? (not freaking likely, but I’ve had to change a double to a decimal WAY to many times to make an annoyingly type specific database happy at this point in my life — and yes, that was a run on sentence. And I did it on purpose to make just to see your face turn blue).
Here is the rub, I can declare a method that does just what I want it to, and it works perfectly. Here is is:
void LoadComboBox<N, V>(List<NameValue<N, V>> list);
Now I can pass the data to the view and the view will be blissfully unaware what is happening to it. Just like a good alien abduction.
Now I thoroughly believe both of my readers are way smarter than me and are only reading my blog out of pity for me (instead of pity, send money. No, really). But if you are wondering how I am loading the generic data into the drop down list and still keeping it generic, here is another method for you:
protected void LoadListControl<N,V>( ListControl ctrl, List<NameValue<N, V>> list) { ctrl.DataTextField = "Name"; ctrl.DataValueField = "Value"; ctrl.DataSource = list; ctrl.DataBind(); }
Very simply, this will take any generic list of NameValue objects and assign it to any control that inherits from ListControl (like a drop down list). As a bonus, I can now assign the data coming in from the presenter to the drop down list in one line of code:
Now my ComboBoxData property can look like this (assume SampleDropDownList is a DropDownList control):
public List<NameValue<string, string>> ComboBoxData { set { LoadListControl(SampleDropDownList, value); } }
Of course, if you are a real slime-ball, and are using C# 3.0 before God intended (meaning: before I get to), you could change the LoadListControl method defined above and turn it into an extension method that extends the ListControl itself. You would need to put this code in a static class, reference the classes namespace, and add the eye of newt to work.
public static void LoadNameValue<N, V>(this ListControl ctrl, List<NameValue<N, V>> list ) { ctrl.DataTextField = "Name"; ctrl.DataValueField = "Value"; ctrl.DataSource = list; ctrl.DataBind(); }
Now we can rewrite the view load routine to a simpler piece of code that is easier to move from form to form. It looks like this (assume SampleDropDownList is a DropDownList control):
public void LoadComboBox<N, V>(List<NameValue<N, V>> list) { SampleDropDownList.LoadNameValue(list); }
So what do we have now? We have the ability to load a DropDownList, from a presenter, using true name/value data pair, and only the presenter knows what the data really is. If I could do that through a property, and not a method, I would be happier, but I will take this as a close second.
As for the rest of the data on my view, I’m stuck with sending data in strings, ints, doubles, DateTime, and making liberal use of IEnumerable (for setting data in a GridView).
Panacea this ain’t; and it isn’t like we are using a dynamic language. But this does give a glimpse of both worlds. I stick with my previous statement. If the view doesn’t need to care what the data type is, then it shouldn’t be forced to. Of course, the presenter should always care. It is the gate keeper that makes sure the data is correct.
And for all of you who are using C# 3.0 before I get to, whose current client laughs in face of new technology and says “bring it on”, and show no fear about tip-toeing on the bleeding edge: Extension Methods are AUSOME BABY. LINQ and Lambda are really cool, don’t me wrong, very powerful. But day in day out what are you going to use the most? Extension Methods. You are going to get a lot of mileage out of these things.



Pingback: » Daily Bits - January 31, 2008 Alvin Ashcraft’s Daily Geek Bits: Daily links, development, gadgets and raising rugrats.