CODEGATOR

.NET info worth sinking your teeth into!
Welcome to CODEGATOR Sign in | Join | Help
in Search

Martin Cook

Yet another C# developer with a blog.

Rant: The evils of capability queries.

Every now and then, when I'm not thinking clearly, I'll find myself including a property with an enumerated type in my code, like this:

enum MyEnum { File, DB }

class MyControl : Control
{
   MyEnum saveType;

   public MyEnum SaveType 
   {
      get {return saveType;}
      set {saveType = value;}
   }
}

Enumerated properties like the one I've just shown are very common in .NET, which is unfortunate, because most of those properties are used to feed code that performs a capability query. Like this:

void DoSave(MyControl mc)
{
   switch (mc.SaveType)
   {
      case MyEnum.File : 
         // Save to a file...
         break;
      case MyEnum.DB :
         // Save to a database...
         break;      
   }
}

Can you see the problem(s) with the code sample above? Actually that's a trick question because the problems I'm alluding to are related to design - not code. I won't go into details (we would all be bored), just remember that capability queries are evil and should be avoided whenever possible. If you don't know what a capability query is then here are some links: Here, or Here or GOOGLE the term "capability query".

I know, I know, Microsoft uses this enumerated, capability query infested approach EVERYWHERE in .NET. That's why I blame Microsoft! Luckily, we don't have to follow Microsoft off that cliff with all the other lemmings. There are better ways of coding available to us!

Now, before I continue, don't think I'm saying that enumerations are bad. They aren't. They're fine - except when they are used to feed code that uses the enumerated information to perform a capability query. That's the part that's bad. Got It?

Alright, so what do we do then? Well, here is a better solution for the save example above. Notice that this approach does NOT perform a capability query:

abstract class SaveBase
{
   public abstract DoSave(); 
}

class FileSave : SaveBase
{
   public override DoSave()
   {
      // Save to a file.
   }
}

class DBSave : SaveBase
{
   public override DoSave()
   {
      // Save to a db.
   }
}

void DoSaveBetter(MyControl mc)
{
   Type type = // Convert the mc.SaveType property to a type.
   SaveBase saveBase = (SaveBase)Activator.CreateInstance(
                type
                );
   saveBase.DoSave(); // See ma, no CQ!
}

So why is the second approach better? Because I have isolated the code for file-saving into the FileSave class, and the code for db-saving into the DBSave class. I've also removed any specialized knowlege from the DoSaveBetter method - where it shouldn't have been in the first place. Even better, when I come back later and add another kind of save (say IsolatedStorage), I can just add a class called IsoSave to the project and I don't have to do ANYTHING to the DoSaveBetter method. Enough said? I hope so.

You may have noticed that I left out the part where I converted the enumerated property to a Type. There are several ways to perform such a conversion but I think the best way is to avoid the use of an enumerated type altogether. After all, if we come back at a later date and add a new way to perform a save then we still have to re-code the enumeration, and of course, test all the code that uses that enumeration. Blah! :o(

I would probably use a string type for the SaveType property in the MyControl class, and use that string to hold the type information needed to get a Type instance at runtime. Now, if you write as many custom Controls as I do, you are probably wondering how to perform a reasonable type conversion for such a property in order to present the control in the Visual Studio designer. Never fear, I have a class for that purpose, and I'll blog about that code later this week.

 

Whew! Sorry about the rant today Embarrassed It's just that sometimes Microsoft's love of capability queries just chaps my bahookie! Angry

 

See ya!

 

Published Aug 27 2007, 10:30 AM by Martin
Filed under: , , ,

Comments

No Comments

Leave a Comment

(required) 
(optional)
(required) 
Submit

About Martin

I work as a software engineer specializing in designing and building object-oriented business solutions for Windows platforms using C#. I have been programming professionally for roughly 20 years.

This Blog

Syndication

Terms of Service | Privacy Statement