0

I want to create an enumeration like object but with an additional "property".

For example I could have a day of the week enumeration:

enum Day {Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday };

Now, let's say I have another property I want to store against each day. Something that never changes. For the sake of the argument let's say we have a pay rate which never changes and is 1.5 on Saturday, 2 on Sunday and 1 otherwise.

Can't do this with enumeration. I was thinking of creating a "helper" static class that would just return this second property, but this seems clunky.

static class Rate
{
    static float GetRate(Day d)
    {
        switch (d)
        {
            case Day.Saturday:
                return 1.5f;
            case Day.Sunday:
                return 2f;
            default:
                return 1f;

        }
    }
}

Instead of enum with helper class I could use a ReadOnlyCollection but that seems complicated and heavy-weight for what I need.

What is the best way to go here?

Sethu Bala
  • 457
  • 3
  • 17
under
  • 2,519
  • 1
  • 21
  • 40

4 Answers4

3

C# enum values are simple single-values unlike in other languages where they can be complex-types (e.g. tuples).

If the enum value represents a "key" for immutable data, you could hack it by using an extension method with a switch block - similar to your example, but syntactically cleaner when used:

enum Day {Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday };

public static class DayExtensions
{
    public static Single GetRate(this Day d)
    {
        switch( d )
        {
            case Day.Saturday:
                return 1.5f;
            case Day.Sunday:
                return 2f;
            default:
                return 1f;
        }
    }
}

Usage:

Day d = Day.Monday;
Single rate = d.GetRate();
Dai
  • 141,631
  • 28
  • 261
  • 374
  • This is in fact a very common way to extend enum functionality. You keep the extension class in the same source code file as the enum, because they are logically part of the same type. – Matthew Watson Dec 16 '16 at 09:33
2

What you can do is add a custom attribute to the enum values like so:

enum Day {
    [MyAttr(Rate=1.5f)]
    Sunday, 
    [MyAttr(Rate=2)]
    Monday
}

public class MyAttr : Attribute {
    public float Rate {get;set;}
}

Then read the attribute like this:

public float GetRate(Day day) {
    MemberInfo memberInfo = typeof(Day).GetMember(day.ToString()).FirstOrDefault();

    if (memberInfo != null) {
        MyAttr attribute = (MyAttr)memberInfo
            .GetCustomAttributes(typeof(MyAttr), false)
            .FirstOrDefault();
        return attribute.Rate;
    }

    return 0;
}
Robba
  • 7,684
  • 12
  • 48
  • 76
1

Perhaps something like:

public struct Day
{
    public Day(int key, float rate)
    {
        _key = key;
        _rate = rate;
    }
    private readonly int _key;
    private readonly float _rate;
    public int Key => _key;
    public float Rate => _rate;

    public static readonly Day
        Monday = new Day(0, 1f),
        Tuesday = new Day(0, 1f), ...;

    public static implicit operator int(Day day) => day.Key;
}

Then Day.Monday.Rate works, and int day = Day.Monday works.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
1

You can use a sealed class with predefined static instances. The extra property (or properties) can be read either as property, or via implicit conversion.

public sealed class Day
{
    private Day(float rate)
    {
        m_Rate = rate;
    }

    private readonly float m_Rate;
    public float Rate { get { return m_Rate; } }

    public static readonly Day Saturday = new Day(1.5f);
    public static readonly Day Sunday = new Day(2f);
    public static readonly Day Monday = new Day(1f);
    public static readonly Day Tuesday = new Day(1f);
    public static readonly Day Wednesday = new Day(1f);
    public static readonly Day Thursday = new Day(1f);
    public static readonly Day Friday = new Day(1f);

    public static implicit operator float(Day day)
    {
        return day.m_Rate;
    }
}

Usage:

var day = Day.Sunday;
var rate = day.Rate;      // Use property
float rate2 = day;        // Use implicit conversion
Maarten
  • 22,527
  • 3
  • 47
  • 68