A long time ago, on my first programming job I had a design problem that I couldn’t solve. This problem haunted me. The reason was that it seemed so simple, and yet I couldn’t find a good solution for it.

Eventually I did a huge refactor, but instead of solving it correctly I simply changed one problem to another.

Recently, years later, in a different company, I came up with that great solution I was after.
So besides telling you I’m thinking about code from years ago way too much, I want to share with you my exciting great solution.

The challenge

Let’s say we have a Car class and we want info about our engine.
We can have a Diesel engine, A V-Type Engine, a Straight engine and so on.

Disclaimer: I don’t really understand anything about car engines

Our challenge is: How to represent our engine type?

Consider that I want my engine type to have functionality.
Example of what EngineType should be able to do:

  • GetHorsePower()
  • GetPrice()
  • GetPriceForUsed(int yearsOld)
  • CalculateAccelerationWithCarWeight(int carWeight)

Option #1: Inheritance

We can have base classes for our engines and the Car will inherit from them. Like this:

public abstract class DieselEngineCar : ICar
{
    public int GetHorsePower() { return 80; }
    public int GetPrice() { return 5000; }
}

public abstract class V8EngineCar : ICar
{
    public int GetHorsePower() { return 200; }
    public int GetPrice() { return 20000; }
}

public class Toyota : V8EngineCar
{
}

Hmmm that sure is interesting but it feels wrong.

What if we want to add GearType and WheelsType? I can’t do multi-inheritance in C#. And even if I could, this design doesn’t feel right. An Engine is part of a car. A car is not a sub-class of an Engine.

This leads us to option #2.

Option #2: Enums

We’ll have an Enum with all our engine types.
And our ICar will have an EngineType property

public enum EngineType { Diesel, V8, Straight, Boxer }
public interface ICar
{
    EngineType Engine { get; }
}

That’s better. But what about that functionality I wanted like Car.Engine.GetPrice() or Car.Engine.GetHorsePower().

First thought that comes to mind is extension methods for our enum:

public static int GetPrice(this EngineType engineType)
{
    switch(engineType)
    {
        case EngineType.Diesel: return 5000;
        case EngineType.Boxer: return 10000;
        default:
        case EngineType.V8:
            return 20000;
    }
}
public static int GetHorsePower(this EngineType engineType)
{
    switch (engineType)
    {
        case EngineType.Diesel: return 80;
        case EngineType.Boxer: return 100;
        default:
        case EngineType.V8:
            return 200;
    }
}

And now MyCar.Engine.GetHorsePower() will work great!

Ok, so this will work but I don’t like it too much. We’ll have helper classes with lots and lots of switch-case statements.
Whenever we add a new engine type, we’ll have to go to each switch-case and add the new engine. What if we forget? Besides, we’re object-oriented and this doesn’t feel very object orienty…
Hmm let’s try solving with classes..

Option #3: Classes

Should be pretty straightforward, right?

public interface ICar
{
    IEngineType Engine { get; }
}

public interface IEngineType
{
    int Price { get; }
    int HorsePower { get; }
}

public class V8Engine : IEngineType
{
    public int HorsePower { get { return 200; } }
    public int Price { get { return 20000; } }
}

public class Hyundai : ICar
{
    public Hyundai()
    {
        Engine = new V8Engine();
    }
    public IEngineType Engine { get; set; }
}

This looks much better. But still, there are a few things I don’t like

  • Why do I need to create a new instance of V8Engine? It’s always the same… Looks wasteful
  • How do I compare two engines? I’ll need something like
    if (engine1.GetType() == engine2.GetType())
    That’s weird, right?

What if I turn all my classes to Singletons??

public class V8Engine : IEngineType
{
    private static readonly Lazy<V8Engine> _instance =
        new Lazy<V8Engine>(() => new V8Engine());
    public static V8Engine Instance => _instance.Value;

    private V8Engine()
    {
    }
    public int HorsePower { get { return 200; } }
    public int Price { get { return 20000; } }
}

I like this more. To compare two engines I can do use a simple == operator since there’s just the one instance.

What I still don’t like is that anyone can inherit from IEngine and create their own custom EngineType.

If you know Java, you might be thinking “In Java, I just extend my enum. C# sucks.”
And truth be told, in Java this is really simple to solve

public enum Level {
    HIGH  (3),  //calls constructor with value 3
    MEDIUM(2),  //calls constructor with value 2
    LOW   (1)   //calls constructor with value 1
    ; 
    private final int levelCode;

    Level(int levelCode) {
        this.levelCode = levelCode;
    }
    
    public int getLevelCode() {
        return this.levelCode;
    }
}

Isn’t it cool? I think so.

You can’t do that in C#. Or can you?

Option #4: Java-like enums in C#

With a little nested class magic you can achieve just that. Here’s how:

public abstract class EngineType
{
    public static EngineType V8 = new V8EngineType();
    public static EngineType Diesel = new DieselEngineType();

    private EngineType()
    {
    }
    public abstract int Price { get; }
    public abstract int HorsePower { get; }

    public class V8EngineType : EngineType
    {
        public override int HorsePower { get { return 200; } }
        public override int Price { get { return 20000; } }
    }

    public class DieselEngineType : EngineType
    {
        public override int HorsePower { get { return 80; } }
        public override int Price { get { return 5000; } }
    }
}

Or alternatively:

public class EngineType
{
    public static EngineType V8 = new EngineType(20000, 200);
    public static EngineType Diesel = new EngineType(5000, 80);

    private EngineType(int price, int horsePower)
    {
        Price = price;
        HorsePower = horsePower;
                 
    }
    public int Price { get; private set; }
    public int HorsePower { get; private set; }
}

The constructor should be private so that no one out of this class could create a new EngineType.

So this is it. This solves my Type design problem, for me at least. If you have other ideas on ways to implement this, I’ll love to hear them.

Some more issues about this approach:

  • By using partial class you can place your nested classes in different files
  • Switch-case won’t work like in a regular enum and there’s no way around it
  • Another trick, which I didn’t show is to use a regular enum with attributes
    http://stackoverflow.com/questions/469287/c-sharp-vs-java-enum-for-those-new-to-c/4778347#4778347
    For example ```
    public enum EngineType
      {
          [EngineAttr(80, 5000)]  Boxer,
          [EngineAttr(100, 10000)]  Straight,
          [EngineAttr(200, 20000)] V8,
      }
      ```
    
      And with extension methods we can get access to the attribute values.
    
    

(CW)