简体   繁体   中英

Is it possible to use Enum with Pair Values like dictionary

In c# I'm a little puzzled to understand Enum.

In my specif case I would need store constant value in a Name Value format like>

300 seconds = 5 minutes

At the moment I use this class.

  • Would be possible to use Enum instead, so I the Enum class would look likes?
  • Can I store in an Enum a Pair Values?

Could you provide me a sample of code?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace MyWebSite.Models
{
    public class Reminders
    {
        private sortedDictionary<int, string> remindersValue = new SortedDictionary<int, string>();

        // We are settign the default values using the Costructor
        public Reminders()
        {
            remindersValue.Add(0, "None");
            remindersValue.Add(300, "5 minutes before");
            remindersValue.Add(900, "15 minutes before");
        }

        public SortedDictionary<int, string> GetValues()
        {
            return remindersValue;
        }

    }
}

You could use a Tuple<int, int> as dictionary key( at least with .NET >= 4 ).

But since you actually want to store a TimeSpan , use that as key.

private static Dictionary<TimeSpan, string> TimeSpanText = new Dictionary<TimeSpan, string>();

static Reminders()
{
    TimeSpanText.Add(TimeSpan.Zero, "None");
    TimeSpanText.Add(TimeSpan.FromMinutes( 5 ), "5 minutes before");
    TimeSpanText.Add(TimeSpan.FromMinutes( 15 ), "15 minutes before");
    TimeSpanText.Add(TimeSpan.FromMinutes( 30 ), "30 minutes before");
    TimeSpanText.Add(TimeSpan.FromHours( 1 ), "1 hour before");
    // ....
}

public static string DisplayName(TimeSpan ts)
{
    string text;
    if (TimeSpanText.TryGetValue(ts, out text))
        return text;
    else
         throw new ArgumentException("Invalid Timespan", "ts");
}

You can get the translation in this way:

var quarter = TimeSpan.FromMinutes(15);
string text = TimeSpanText[ quarter ];

You can decorate your enumeration with description attributes and access them later through reflection. For example,

enum ReminderTimes
{
    [Description("None")]
    None = 0,

    [Description("5 minutes before")]
    FiveMinutesBefore = 300,

    [Description("15 minutes before")]
    FifteenMinutesBefore = 900
}

You can get the description by:

public static string GetDescription(this Enum value)
{            
    FieldInfo field = value.GetType().GetField(value.ToString());

    DescriptionAttribute attribute
            = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute))
                as DescriptionAttribute;

    return attribute == null ? value.ToString() : attribute.Description;
}

See also: http://www.codeproject.com/Articles/13821/Adding-Descriptions-to-your-Enumerations

An enum is actually a named integer type. Eg

public enum Foo : int 
{
   SomeValue = 100,
}

which means that you create a Foo enumeration with the type 'int' and some value. I personally always make this explicit to show what is happening, but c# implicitly makes it the 'int' type (32-bit int).

You can use any name for the enum names and can check if it is a valid enum by using Enum.IsDefined (eg to check if 300 is a valid enum name).

update

Okay, actually that's not 100% correct to be honest. This update is just to show what's actually happening under the hood. An enum is a value type with fields that act as names. Eg the above enum is actually:

public struct Foo 
{ 
    private int _value;
    public static Foo SomeValue { get { return new Foo() { _value = 100 }; } }
}

Notice that the 'int' is the type of the int (in my case explicit). Because it's a value type, it has the same structure as a real integer in memory - which is probably what's being used by the compiler when you're casting.

If you are asking can you store an integer value against an enum then yes you can eg

 public enum DurationSeconds
 {
     None = 0,
     FiveMinutesBefore = 300,
     FifteenMinutesBefore = 900,
     ThirtyMinutesBefore = 1800,
     OneHourBefore = 3600,
     TwoHoursBefore = 7200,
     OneDayBefore = 86400,
     TwoDaysBefore = 172800
 }

Contrary of what I usually do, I'll add another answer, which is IMO the answer to the problem.

You usually want the compiler to do as much checking as you can before actually using run-time checking. That means in this case using Enum's for getting values:

// provides a strong type when using values in memory to make sure you don't enter incorrect values
public enum TimeSpanEnum : int
{
    Minutes30 = 30,
    Minutes60 = 60,
}

public class Reminders
{
    static Reminders()
    {
        names.Add(TimeSpanEnum.Minutes30, "30 minutes");
        names.Add(TimeSpanEnum.Minutes60, "60 minutes");
    }

    public Reminders(TimeSpanEnum ts)
    {
        if (!Enum.IsDefined(typeof(TimeSpanEnum), ts))
        {
            throw new Exception("Incorrect value given for time difference");
        }
    }

    private TimeSpanEnum value;
    private static Dictionary<TimeSpanEnum, string> names = new Dictionary<TimeSpanEnum, string>();

    public TimeSpan Difference { get { return TimeSpan.FromSeconds((int)value); } }
    public string Name { get { return names[value]; } }

}

When creating the program like this, the language helps you in a couple of ways:

  • You cannot use timespans that aren't defined
  • It initializes the dictionary only once, to be exact: when the type is constructed
  • The Enum.IsDefined makes sure you dont use an incorrect int value (eg new Reminders((TimeSpanEnum)5) will fail.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM