Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Behaviour to simulate an enum implementing an interface

Say I have an enum something like:

enum OrderStatus
{
    AwaitingAuthorization,
    InProduction,
    AwaitingDespatch
}

I've also created an extension method on my enum to tidy up the displayed values in the UI, so I have something like:

public static string ToDisplayString(this OrderStatus status)
{
    switch (status)
    {
        case Status.AwaitingAuthorization:
            return "Awaiting Authorization";

        case Status.InProduction:
            return "Item in Production";

        ... etc
    }
}

Inspired by the excellent post here, I want to bind my enums to a SelectList with an extension method:

public static SelectList ToSelectList<TEnum>(this TEnum enumObj)

however, to use the DisplayString values in the UI drop down I'd need to add a constraint along the lines of

: where TEnum has extension ToDisplayString

Obviously none of this is going to work at all with the current approach, unless there's some clever trick I don't know about.

Does anyone have any ideas about how I might be able to implement something like this?

like image 357
fearofawhackplanet Avatar asked Jun 09 '10 15:06

fearofawhackplanet


People also ask

How do you implement interface in enum?

Enum, it can not extend any other class or enum and also any class can not extend enum. So it's clear that enum can not extend or can not be extended. But when there is a need to achieve multiple inheritance enum can implement any interface and in java, it is possible that an enum can implement an interface.

Can enum type implement interface?

Yes, Enum implements an interface in Java, it can be useful when we need to implement some business logic that is tightly coupled with a discriminatory property of a given object or class.

Can an enum implement an interface C#?

After a bit of experimentation, my conclusion is that it's possible for an enum to implement an interface if it doesn't have methods. But you cannot create it in C#. Using that enum in a C# program is funny: if you check if the value "is IMyInterface", the compiler warns you that the expression is never of that type.

Can we declare enum in interface Java?

It's perfectly legal to have an enum declared inside an interface . In your situation the interface is just used as a namespace for the enum and nothing more. The interface is used normally wherever you use it.


3 Answers

Is there a compelling reason to use an enum here?

When you start jumping through crazy hoops to use enums, it might be time to use a class.

public class OrderStatus
{
    OrderStatus(string display) { this.display = display; }

    string display;

    public override string ToString(){ return display; }

    public static readonly OrderStatus AwaitingAuthorization
        = new OrderStatus("Awaiting Authorization");
    public static readonly OrderStatus InProduction
        = new OrderStatus("Item in Production");
    public static readonly OrderStatus AwaitingDispatch
        = new OrderStatus("Awaiting Dispatch");
}

You consume it the same as an enum:

public void AuthorizeAndSendToProduction(Order order, ProductionQueue queue)
{
    if(order.Status != OrderStatus.AwaitingAuthorization) 
    {
        Console.WriteLine("This order is not awaiting authorization!");
        return;
    }
    order.Status = OrderStatus.InProduction;
    queue.Enqueue(order);
}

The string representation is built-in, and all you need is ToString().

like image 138
Jay Avatar answered Oct 17 '22 18:10

Jay


Of course, you can use the DisplayAttribute to annotate your Enums.

enum OrderStatus
{
    [Display(Description="Long Desc", Name="Awaiting Authorization", ShortName="Wait Auth")]
    AwaitingAuthorization,

    [Display(Description="...", Name="...", ShortName="...")]
    InProduction,

    [Display(Description="...", Name="...", ShortName="...")]       
    AwaitingDespatch
}

You can also opt to create an extension method taking any enumeration value and returning its display name based on the attribute set to it to tidy up the displayed values in the UI, as follows:

public static class EnumExtensions
{
    public static string ToName(this Enum enumValue)
    {
        var displayAttribute = enumValue.GetType()
            .GetMember(enumValue.ToString())[0]
            .GetCustomAttributes(false)
            .Select(a => a as DisplayAttribute)
            .FirstOrDefault();
        return displayAttribute?.Name ?? enumValue.ToString();
    }
}

With

public enum Test
{
    [Display(Name="AAA")]
    a,
    b
}

Code:

Console.WriteLine(Test.a.ToName());
Console.WriteLine(Test.b.ToName());

Results

AAA

b

I want to bind my enums to a SelectList with an extension method:

For type safety, I wouldn't use an extension methods, but instead a static class that deals with the Enum type:

Pre C# 7.3 version. Since Enum is not a valid type constraint prior to 7.3 (and it would cause a compile-time exception), you'll end up by considering that enums are value types and they implement some interfaces, in order to restrict the type parameter as close to Enum as possible.

public static class Enums<TEnum> where TEnum : struct, IComparable, IFormattable, IConvertible
{
    static Enums()
    {
        if (!typeof(TEnum).IsEnum)
        {
            throw new InvalidOperationException();
        }
    }
}

C# 7.3+ version, with compile time checking... yay!

public static class Enums<TEnum> where TEnum : Enum
{
}

GetValues Method for the class:

public static IEnumerable<TEnum> GetValues(bool includeFirst)
{
    var result = ((TEnum[])Enum.GetValues(typeof(TEnum))).ToList();
    if (!includeZero)
        result = result.Where(r => r != default).ToList();
    return result;
}

If you follow Enum Guidelines and include the Default (zero) value, we can ignore it (sometimes we want to display the value like "None Selected" and sometimes we don't "Invalid Selection").

Then we can add another method:

public static IEnumerable<string> GetNames(bool includeFirst)
{
    var result = GetValue(includeFirst)
       .Select(v => v.ToName())
       .ToList();
    return result;
}
like image 31
Erik Philips Avatar answered Oct 17 '22 20:10

Erik Philips


Instead of using "ToDisplayString", simply override ToString() of your enum. So if an enum overrides it it will take it, otherwise it will take the default ToString behavior (in ToSelectList).

like image 1
Mike Gleason jr Couturier Avatar answered Oct 17 '22 18:10

Mike Gleason jr Couturier