Ayende @ Rahien

Refunds available at head office

Emulating Java Enums

Java Enums are much more powerful than the ones that exists in the CLR. There are numerous ways of handling this issue, but here is my approach.

Given this enum (defined in Java):

private static enum Layer {
    FIRST,
    SECOND;

	public boolean isRightLayer(WorkType type) {
		if (this == FIRST && type != WorkType.COLLECTION) return true;
		return this == SECOND && type == WorkType.COLLECTION;
		}
}

And the C# version is:

private class Layer
{
    public static readonly Layer First = new Layer(delegate(WorkType type)
    {
        return type != WorkType.Collection;
    });
    public static readonly Layer Second = new Layer(delegate(WorkType type)
    {
        return type == WorkType.Collection;
    });

    public delegate bool IsRightLayerDelegate(WorkType type);

    private readonly IsRightLayerDelegate isRightLayer;

    protected Layer(IsRightLayerDelegate isRightLayer)
    {
        this.isRightLayer = isRightLayer;
    }

    public bool IsRightLayer(WorkType type)
    {
        return isRightLayer(type);
    }
}

Comments

Niki
09/29/2008 10:34 PM by
Niki

Why don't you just declare an extension method on you enum?

private static enum Layer { FIRST, SECOND }

private static class LayerExtensions {

public static bool isRightLayer(this Layer layer, WorkType type) {

  if (layer == FIRST && type != WorkType.COLLECTION) return true;

  return layer == SECOND && type == WorkType.COLLECTION;

}

}

I know it's not the same internally, but the syntax would be more or less the same.

Ayende Rahien
09/29/2008 11:15 PM by
Ayende Rahien

Java enums also have state, which extension methods do not have.

Hendry Luk
09/30/2008 12:30 AM by
Hendry Luk

Having said that, there's nothing stopping us from implementing it the same way as java counterpart:

private static class Layer

{

 public static readonly Layer FIRST = new Layer();

 public static readonly Layer SECOND = new Layer();


public boolean IsRightLayer(WorkType type) {

    if (this == FIRST && type != WorkType.COLLECTION) return true;

    return this == SECOND && type == WorkType.COLLECTION;

}

}

David
09/30/2008 02:04 AM by
David

How about using extension methods?

public static class LayerExtensions

{

public static bool IsRightLayer(this Layer layer, WorkType workType)

{

if (layer == Layer.FIRST && workType != WorkType.COLLECTION) return true;

return layer == Layer.SECOND && workType == WorkType.COLLECTION;

}

}

David
09/30/2008 02:04 AM by
David

Oops, shoulda refreshed before posting :-\

Matthew Podwysocki
09/30/2008 03:03 AM by
Matthew Podwysocki

This is why I like F# for this purpose using discriminated unions. Such code as this works perfectly for modeling what was above:

light

type WorkType =

| Collection

| NonCollection

type Layer =

| First

| Second

with member x.IsRightLayer(workType) =

  match (x, workType) with

  | l, w when l = First && w <> Collection -> true

  | l, w -> l = Second && w = Collection

Then I can use it such as this:

let result = Layer.Second.IsRightLayer(WorkType.Collection)

Matt

Justin Rudd
09/30/2008 05:10 AM by
Justin Rudd

The C# enum isn't quite a replacement for the Java one.

As it is, it can't be serialized. Adding serializable is just one part. You'd also have to implement whatever the equivalent of readObject and writeObject are to ensure the same instance is returned no matter what.

It can't be used in a switch statement.

You could use the same delegate trick to add methods to get polymorphism like you can with Java enums ( http://langrsoft.com/articles/enum2.shtml), but that breaks down pretty quick if you get beyond a few methods.

Andrey Shchekin
09/30/2008 08:25 AM by
Andrey Shchekin

Good choice. Enums are antipattern for most situations anyway, since they lead to having unextensible switch-by-enum instead of using polymorphism.

Mike Brown
09/30/2008 11:11 AM by
Mike Brown

Quick question. What are your thoughts on using the Func <t derivatives for delegate declaration?

So instead of:

public delegate bool IsRightLayerDelegate(WorkType type);

private readonly IsRightLayerDelegate isRightLayer;

You just have

private Func <worktype,bool> isRightLayer;

Mike Brown
09/30/2008 01:35 PM by
Mike Brown

Just realized that my code got mangled by html

private readonly Func<WorkType,bool> isRightLayer;

Fred Hirschfeld
09/30/2008 02:26 PM by
Fred Hirschfeld

Bruce,

The extension version looks very nice and you could improve it slightly by adding a custom attribute to the code that would decorate the enum member:

public enum Planet

{

[PlanetMeasurements(3.303e+23, 2.4397e6)]

Mercury,


[PlanetMeasurements(4.869e+24, 6.0518e6)]

Venus

}

Then in the extension methods you would simply access these attributes and use their values thus eliminating the need for the switch statements.

Ayende Rahien
09/30/2008 02:36 PM by
Ayende Rahien

This code is for the .NET 2.0, no Func

Germ&#225;n Schuager
10/07/2008 03:19 PM by
Germán Schuager

How would you map a class with a property of such "enum" type in NHibernate?

Comments have been closed on this topic.