More about type descriptors
The other day, one of my readers posed a question regarding my recent post “Data Binding to Custom Objects” – The question was essentially “Why are you writing all this code? There’s much simpler ways to do the same thing.” Well, the reader is correct. There are many ways to do this same thing. We’ll go over that in a second. First, let me take a shot at defending myself. All over the web, there’s thousands of web sites and articles, blogs and newsgroups, discussion lists and bulletin boards all about “how to do stuff in .NET.” This is great, and it helps you find the information you’re looking for to solve the problem that you currently have in front of you in your day to day jobs. However, the truly great programmers are the ones who know what’s going on behind the scenes. Managed languages such as Java, VB and C# get a lot of criticism from the more “pure programmers” who prefer to work more low level with C and assembly. Some claim there’s an entire generation of programmers who will never write their own memory manager, never create a linked list class from scratch, don’t know how a hash table works internally, don’t know how pointers really work, and don’t know the difference between memory allocated on the stack and memory allocated on the heap. I would disagree and say that it’s not the language itself that’s directly responsible for this new “generation” of programmers, but the complexity of the APIs they depend on. If you took the .NET framework out of C#, you’d have nothing more than a object-oriented language that still relies on the developer to construct these sorts of collection objects and design algorithms. This is no different than the plethora of ready made objects MFC provides for C++ Windows programmers. A language is simply an abstract way of expressing an idea, but those more familiar with the internal workings of a language will be the ones who can exact their ideas in a clear and more precise manner. Just because the .NET framework comes with a Hashtable class doesn’t mean you shouldn’t know how to write your own, and just because the .NET framework can take care of property descriptors for you doesn’t mean you shouldn’t learn how they work.
This new generation is not because of lazy programmers, or programmers who didn’t learn the basics. Programmers in general will learn what they need to do their job, and no matter how low level you get, there’s always a level of abstraction. Assembly programmers said this about C, C programmers said this about VB. Until you want to write everything in pure machine code, running in ring 0, on your own CPU design that you soldered together in your basement, you’re relying on a framework that makes your job easier. What’s to blame is this concept of “rapid application design” which VB started. It became critical to toss together these quick little applications in a fraction of the time it would take with more low level languages. IDEs started doing the boring work for you, which is great as long as you know what’s going on. Which leads me back to my original point – there’s plenty of places on the net to find out how to do something, this blog is dedicated to explaining how things works underneath. There’s only so far you will get memorizing what APIs to use where, but I promise you it’s always worth the time to really dig into something and learn what’s going on, for when you need to modify how something behaves or figure out how to fine tune something, you’ll have a pretty good idea of how to do that.
So use my article as a learning tool, this is how the data binding code works internally and this is how ADO.NET works inside. Now, if you’re simply wanting to bind a collection of simple objects to a grid, you can rely on “default type descriptors” rather than generating your own custom type descriptor as described in my article.
Take the following class:
class Company
{
private string _name;
private string _address;
public string Name { get { return _name; } }
public string Address { get { return _address; } }
public Company(string name, string address)
{
_name = name;
_address = address;
}
}
It couldn’t be simpler, it has two string properties and a constructor. I can bind it to the Data Grid like so:
protected void Page_Load(object sender, EventArgs e)
{
List<Company> list = new List<Company>();
list.Add(new Company("Microsoft", "123 Main"));
list.Add(new Company("IBM", "333 Main"));
Grid.DataSource = list;
Grid.DataBind();
}
My grid doesn’t change, it still binds to the “Name” and “Address” property of the object. Internally, the grid still asks List<> for an enumerator, which List<> provides. Each “Company” object in the list doesn’t provide a custom type descriptor, so a default type descriptor is used. This type descriptor will look for a public method matching the names of the bound fields. Note this must be a method, not a property (if I mark _name public and bind to that, I’d get a runtime error.) This works great for the simple case, but those who used this method without first writing their own custom type descriptor would have no idea why this works, or how they can manipulate or extend this system to do exactly what they wanted. Suppose later on, I wanted to provide some dynamic array of properties, such as items created by the user, or retrieved from a database. I’d be totally lost and never know how to create my own custom type descriptors. Hopefully some people out there got some use from my post, and there will be some better, more efficient code out there because of my efforts.
Thanks for the comments,
Mike Christensen – Web Dev Guy
Comments
- Anonymous
June 02, 2006
Just to be clear, you're not using the right terms. The _name is a field, not a property. Thus your sentance: "This type descriptor will look for a public method matching the names of the bound fields. Note this must be a method, not a property" really should be: "This type descriptor will look for a public method matching the names of the bound fields. Note this must be a method, not a field". Specifically, you can use a property because underneath the property get IS a method (and thus has a MethodInfo defined). You could also bind to "free" methods that are not properties just fine (as long as they take zero arguments). - Anonymous
June 12, 2006
Oops you're right - This must be a property, not a field. For some reason the exception .NET throws says "property or field" even though it actually can't be a field. Thanks for catching that!