Thursday, September 11, 2008

When to use Enum's vs object's

Enum’s are a touchy point with .net developers. There are the pure OO types that detest the use of them and then the perhaps more MS inclined that love the little buggers.
I will admit that I am more of the later but I have been rethinking my use of them lately and think I have settled on a few rules of thumbs that I may start to follow, which of course I would like your thoughts on.

Enum’s in the domain.
Enum’s can easily maps to reference tables in most ORM’s and so this is an easy win here. Unfortunately I am starting to lean towards the thought of not using Enum’s in the domain. The presence of Enum’s usually means different means of handling certain scenarios and instead of using ugly switch statements in the domain I am going to try to move to using objects over Enum’s, which may help with using a more robust strategy patterns.
These objects are still easily mapped using discriminators and this means it allows domain functionality in these new more DDD styled value types.
Possibly one approach is to start using Enum’s in the intial stages of mapping and as functionality grows, refactor to objects as necessary.

Enum’s over the wire
Enum’s over the wire I am completely ok with. Provided the Enum’s are well documented these little buggers just go across as the given value type you have assigned (commonly int). This keeps messages sizes down and allows the client to create an Enum on the receiving side to map to give Enum values. NServiceBus is an example of where this happens (for error codes IRC).

Enum’s in the application
I think this is where is would be most pragmatic with my approach. A lot of application developers, especially in the .Net world are more that happy to deal with Enum’s and small switch statement in the application may actually be easier for many to maintain. These may also be easier to deal with on UI displays, like drops downs as many people have standardised helpers to manipulate Enum’s. Again it really depends on the situation and how much logic is dealt with on the client/application.


Again I hope I will take a reasonably pragmatic approach to this. Hard and fast rule often mean you are unnecessarily painting yourself into a corner.

For those wondering what the hell I am talking about when using Objects as Enum’s this nasty code give a vague idea. Note that you can now subclass the type, providing type specific logic.

class Program

{

static void Main(string[] args)

{

Person bob = new Person(OccupationType.Developer, OccupationEnum.Developer);

//do other stuff...

}

public class Person

{

OccupationType occupation;

OccupationEnum occupationEnum;

public Person(OccupationType occupation, OccupationEnum occupationEnum)

{

this.occupation = occupation;

this.occupationEnum = occupationEnum;

}

}

public class OccupationType

{

public static OccupationType RockStar = new OccupationType();

public static OccupationType Developer = new OccupationType();

public static OccupationType BusDriver = new OccupationType();

public static OccupationType Maid = new OccupationType();

}

public enum OccupationEnum

{

RockStar,

Developer,

BusDriver,

Maid

}

}

2 comments:

Gabriel Vonlanten C. Lopes said...

I really liked your idea and i am trying to find the best approach myself, but i think that you approach of using object types on static classes would not work if i want to translate my Linq query to the database, using EntityFramework, because EF would not be able to write any SQL code that could retrive the data you want.

My question with domains is, should i create a table that holds domain information (like Id and Description) and Also enums on the application? or should i just create enums, or just create table domains (that will be translated into POCO objects) ... i cannot find a perfect answer for this, thinks as best practice terms

Unknown said...

It looks like you have hit the wall of EF. Personally I don't think EF is a good fit when using domain models with techniques like this. If you need an ORM consider NHibernate. Either way this logic will only be applied out of the db, unless you made modifications to the linq providers themselves. That being said I don't use domain objects in that manner, you may want to read up on CQRS and see how that applies to you.