CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Jeffrey Palermo [MVP]

Software management consultant and CTO, Headspring Systems

I've been tagged. . . and enumerated classes - level 200

After being tagged my numerous people, here's my 5.  My long-time readers might know some of these if they've been reading closely over the past few years, but here are 5 things about me that aren't widely known:
  • In college, I was a member of the Texas A&M country & western dance team:  www.aggiewranglers.com - I got to travel the country and world performing c&w dance.  I married a girl who was also on the team. (all partner dancing, people, no line dancing).  Think "girl being thrown in the air".
  • In 2003 I was called up for Army service to Iraq - was there 1 year and 3 days.  I'm 1.5 months from separation, so I'm hoping the nothing BIG happens between now and March 3rd.
  • I was using Yahoo before it had e-mail service, and my account is one of those that is really jacked up because my id I originally registered had to be an e-mail address.
  • I started writing database web applications before the dawn of ASP 1.0 - Anybody remember .idc and .htx files? - My CGI work was configuring WODA for a few clients.
  • When I was a kid, I read every book on motorcycles/dirtbikes/ATVs in the public library, and I'd moved on to the adult section.  I was the only young kid who knew the difference between a two-stroke and four-stroke engine.  I now have a motorcycle, love to ride dirtbikes, and I'm lobbying my wife for a Harley.
Now, I'm going to tag Scott Bellware 5 times.

So that this post is now void of technical content, here is a tip for using enumerations in your applications:

Consider the following class: 

    1     public class WorkOrder

    2     {

    3         private Status _status;

    4         private string _description;

    5 

    6         public Status Status

    7         {

    8             get { return _status; }

    9             set { _status = value; }

   10         }

   11         public string Description

   12         {

   13             get { return _description; }

   14             set { _description = value; }

   15         }

   16     }

Notice that we are using a Status class (enum):

    public enum Status

    {

        Pending,

        InProcess,

        CompleteNApproved,

    }

My system manages work orders.  Realize that this is an over-simplified example, but what happens when you need to list our many WorkOrder(s) in a grid or for a printable report?  Easy, right?  No.  You have this Status property that is very ugly when displayed.  "InProcess", "CompleteNApproved".  Your users don't want to see that.  In business speak, it needs to be displayed as "In-Process", and "Complete & Approved".  How do we do this easily in code?  On possible way is to create a Facade class that is used in reports.  This facade class could translate the enum to our required Status titles.  This is undesirable because we then have to wrap each WorkOrder instance in a new class just for display purposes.  I would prefer that our WorkOrder could be displayed on its own, but we have to do something about that enum.  Let's turn our enum into an enumerated class:

First, I'll rename the enum like so:

    public enum StatusValue

    {

        Pending,

        InProcess,

        CompleteNApproved,

    }

Then I'll make Status a class with 3 static instances: 

    public class Status

    {

        private static Status _pending = new Status(StatusValue.Pending, "Pending");

        private static Status _inProcess = new Status(StatusValue.InProcess, "In-Process");

        private static Status _complete = new Status(StatusValue.CompleteNApproved, "Complete & Approved");

 

        private StatusValue _statusValue;

        private string _displayTitle;

 

        private Status(StatusValue statusValue, string displayTitle)

        {

            _statusValue = statusValue;

            _displayTitle = displayTitle;

        }

 

        public StatusValue StatusValue

        {

            get { return _statusValue; }

        }

 

        public string DisplayTitle

        {

            get { return _displayTitle; }

        }

 

        public override string ToString()

        {

            return _displayTitle;

        }

 

        public static Status Pending

        {

            get { return _pending; }

        }

 

        public static Status InProcess

        {

            get { return _inProcess; }

        }

 

        public static Status Complete

        {

            get { return _complete; }

        }

    }

Notice that I've overridden the ToString() method so that my _displayTitle field is returned.  Now, when I throw my WorkOrder class (or List<T> of instances) into a grid or some other binding container, I'll see the proper display title for my Status.  Now my users are happy, and I can move a WorkOrder class around anywhere in my application.  For persisting to the database, I use the StatusValue (which can be Int32, Int16, or byte) in my database table.  It's easy to do that whether I'm using a hand-crafted SQL statement or (my favorite) NHibernate for my ORM solution.

Our lack of built-in enumerated classes is something I plan to gripe about at the up-coming MVP Summit.  Our enum construct is very weak and is no more than glorified primitives.  Consider what Java has as of version 5 (taken from http://java.sun.com/j2se/1.5.0/docs/guide/language/enums.html):

public enum Planet {
MERCURY (3.303e+23, 2.4397e6),
VENUS (4.869e+24, 6.0518e6),
EARTH (5.976e+24, 6.37814e6),
MARS (6.421e+23, 3.3972e6),
JUPITER (1.9e+27, 7.1492e7),
SATURN (5.688e+26, 6.0268e7),
URANUS (8.686e+25, 2.5559e7),
NEPTUNE (1.024e+26, 2.4746e7),
PLUTO (1.27e+22, 1.137e6);

private final double mass; // in kilograms
private final double radius; // in meters
Planet(double mass, double radius) {
this.mass = mass;
this.radius = radius;
}
public double mass() { return mass; }
public double radius() { return radius; }

// universal gravitational constant (m3 kg-1 s-2)
public static final double G = 6.67300E-11;

public double surfaceGravity() {
return G * mass / (radius * radius);
}
public double surfaceWeight(double otherMass) {
return otherMass * surfaceGravity();
}
}

Now we need to play catch-up again.  If in C# I was able to declare my Status enum like this, I could give it a friendly display title and even some methods right there in the enum definition.  I would have less code to maintain, and I would get the build in enum behavior for free.





Comments

Tom Opgenorth said:

Nice trick.  One thing that I have done, along the same lines, is to create my own custom attributes to hold a user friendly display value.  Then I write a helper to pull that information out of the attribute.  Argueably not as flexible as what you've done here, but it got the job done for what I needed to do.

# January 15, 2007 9:22 AM

Daniel Pollock said:

I second the custom attribute idea. Once you have the attribute class set up and a "helper" function to pull the attribute out, the syntax is very similiar like you descibed for the java implementation.

I would argue that the attribute method with use of reflection is just as flexible and easy, if not better. With the process that Jeff describes, you still have to hard-code the values that you want inside of the status class instead of at the enum level. That makes it damn hard to later add on other properties that you'd like to attribute to that enum.

The only room for improvement, I see, on the attribute method is maybe make the process of pulling the attribute through reflection a bit cleaner.

# January 15, 2007 9:48 AM

Jeffrey Palermo said:

Daniel,

Perhaps a code sample of this attribute method?

# January 15, 2007 9:55 AM

Johan Eijlders said:

Hi Jeffrey,

I found this attribute example on the codeproject and used it several times.

http://www.codeproject.com/csharp/enumwithdescription.asp

# January 15, 2007 2:16 PM

Jeffrey Palermo said:

Johan,

Yes, I'm aware of that sample.  In my opinion, it's a bad option.  Yes, it's possible, but only through reflection and only by adding a UI-related property in  your domain class.

With the attribute approach, there is no way to override the display text at runtime or configure it for a particular customer (and forget localization or translation).

# January 15, 2007 2:30 PM

Johan Eijlders said:

Hi Jeffrey,

You're right it should not be in the domain. I asume you're using the class which is some kind of descriptor in the presenter. I like the idea and use it the next time. It is always good to see something new.

# January 15, 2007 2:43 PM

Eric McVicker said:

I'm not sure about adopting an enum scheme like JDK 5.  However, I do have a gripe about .Net Enum and that is the lack of type safety since you can cast any number to one not just a number that is in range.

# January 15, 2007 5:18 PM

Ben Scheirman said:

I wouldn't shy away from the [Description] attribute, Jeffrey.  Sure it's UI related information in the domain, but it doesn't have to be localized.  You could just as easy add a localization constant instead of the string there.

Since that would be such an easy change, I wouldn't worry about it until that was actually a requirement, citing YAGNI with the localization.  (Usually this is an upfront requirement anyway)

# January 15, 2007 9:34 PM

Jeffrey Palermo said:

Ben,

You are right about the YAGNI in most cases, and if this display text never needs to change, I'm sure there is a way to make that solution not feel so dirty, but any time the display text is needed in a view, this reflection code is going to have to be called (or a function that wraps the reflection code).  It's a lot of duplication.

Creating an enumerated class cuts that enumeration and is the solution that Java developers have used pre-JDK5 since 1995.

# January 16, 2007 7:54 AM

Daniel Pollock said:

The codeproject that Johan sites is what I was referring too.  

I commented that the reflection code could be cleaner and I see that as the same problem you sited: having to "add a UI-related property in your domain class.".  

I re-read, in detail, your implementation of a enumerated class and now agree  (guess i jumped on the attribute wagon to soon!)  that its definitely the way it should head.

Should Microsoft copy java's syntax? It seems really clean, and  the syntax seems to be a natural fit into the current .net language. What other features should it contain? ( generics? inheritance?)

# January 16, 2007 9:30 AM

Tom Opgenorth said:

FWIW, in my current project/contract, I'm going to opt with the technique that you show here.  Your "enumerated class" approach does offer some flexibility that I won't get with custom attributes on an enum (most notiably with custom serialization of said value).

# January 16, 2007 7:44 PM

Bill Pierce said:

I do something very similar however, your Status class eliminates the need for a StatusValue enum.

Change Status.Value to an int rather than the enum, implement equals/gethashcode, then change your private statics to public static readonlys, and your other fields to readonly.

Makes the enum superfluous.

I also use this technique to represent well known lookup table entries in code.

# January 17, 2007 2:19 PM

Jeffrey Palermo said:

Bill,

That's pretty darned close to how my team has it in our production app, but I guess I watered it down too much for the blog post.  Yes, equals and GetHashCode() are definitely necessary as now we have value objects and not entities.  I also map the Status class to the database through a StatusType NHibernate translator that knows to take the status code and store it in the database column (and read it back, etc).

# January 17, 2007 4:04 PM

Stano Peťko said:

Hello.

I did something similar with my enums. I have a class EnumClass, which I derive from and fill it with enum values together with their string descriptions. All enum values are in a collection (actually, EnumClass is derived from Collection). This way I can use the final class for each enum as a datasource - for comboboxes.

# January 18, 2007 7:57 AM

Colin Jack said:

We've used the sort of approach you are discussing, moving the description class out of the domain at the same time.

# May 22, 2007 4:15 AM

About Jeffrey Palermo

Jeffrey Palermo is a software management consultant and the CTO of Headspring Systems in Austin, TX. Jeffrey specializes in Agile coaching and helps companies double the productivity of software teams. Jeffrey is an MCSD.Net , Microsoft MVP, Certified Scrummaster, Austin .Net User Group leader, AgileAustin board member, INETA speaker, INETA Membership Mentor, Christian, husband, father, motorcyclist, Eagle Scout, U.S. Army Veteran, and Texas A&M University graduate. Check out Devlicio.us!

This Blog

Syndication