Converting "weekstring" to enum

178 Views Asked by At

I am currently working with some automated jobs sheduled from an SQL-Database.

Each Job as a Column 'RunDays' of type string(nvarchar(7)).

Let's say the value is '1111111' that means 'SMTWTFS' (Sunday,Monday,[...]).

I've created this enum:

public enum RunDays : int
{
    Sunday = 0, 
    Monday = 1,
    Tuesday = 2,
    Wednesday = 3,
    Thrusday = 4, 
    Friday = 5, 
    Saturday = 6     

    //Maybe int is bad here cause Wednesday = 3 & Monday + Tuesday is also 3 -.-      
}

But how to convert to that and vice versa ?

Here's what I tried so far:

if(row["RunDays"] != DBNull.Value)
{
   for(int i = 0; i < row["RunDays"].ToString().Length; i++)
   {
      if(int.Parse(row["RunDays"].ToString()[i].ToString()) == 1)
      {
          job.RunDays = job.RunDays | (RunDays)i;
      }                            
   }
}

Sadly all I am getting is 'Sunday' as the value.

What am I doing wrong/ what am I missing ?

3

There are 3 best solutions below

3
On BEST ANSWER

If you want multiple enum values you need an enum marked with the [Flags] attribute and give each member a value that is a power of 2:

[Flags]
public enum RunDays : int
{
    Sunday = 1, 
    Monday = 2,
    Tuesday = 4,
    Wednesday = 8,
    Thrusday = 16, 
    Friday = 32, 
    Saturday = 64          
}

The [Flags] attribute enables the enum to take values that are not explicitly declared (e.g. 5) and the powers of 2 ensure that each combination is unique.

0
On

The following enum can do what you need:

[Flags]
public enum RunDays : int
{
   Sunday = 1, 
   Monday = 2,
   Tuesday = 4,
   Wednesday = 8,
   Thrusday = 16, 
   Friday = 32, 
   Saturday = 64     
}

Note, that enum has attribute [Flags] that indicates that enum can be treated as bit field (a set of flags). Also, you have to define every constant in powers of two. This enum can have values in range 1-128 that describes all possibilities. To use the enum, you need simply convert integer value to your enum

RunDays days = (RunDays)14;

This returns enum: Monday, Tuesday, Wednesday.

PS. Sunday with 0 value is not a correct value because in this case numeric representation of Sunday is 0, that is default integer value. So, it may lead to unexpected results. Usually it is recommended to use either None or Unknown labels for 0 value (in the case if you really need it).

1
On

As others have already said, you need to use the [Flags] attribute on the enum and make the values powers of two so that Monday+Tuesday!=Wednesday. Using C# 7's new binary literals feature makes this especially convenient:

[Flags]
enum RunDays
{
    None    =       0b00000000,
    Sunday =        0b00000010,
    Monday =        0b00000100,
    Tuesday =       0b00001000,
    Wednesday =     0b00010000,
    Thursday =      0b00100000,
    Friday =        0b01000000,
    Saturday =      0b10000000,
}

Since your index is no longer the same as an the enum value, you can't do a cast anymore; converting to an array is one way to go:

    static readonly List<RunDays> s_runDays = Enum.GetValues(typeof(RunDays)).Cast<RunDays>().ToList();
    static RunDays Parse(string s)
    {
        if (String.IsNullOrWhiteSpace(s)) throw new ArgumentNullException(nameof(s));
        if (s.Length != 7) throw new ArgumentOutOfRangeException(nameof(s));

        var retval = RunDays.None;
        for (int i = 0; i < s.Length; i++)
            if (Int32.TryParse(s[i].ToString(), out var result) && (result > 0))
                retval |= s_runDays[i+1];
        return retval;      
    }

With that, you now get the desired results:

    static void Main(string[] args)
    {
        var monday = Parse("0100000"); // Monday
        var weekends = Parse("1000001");    // Sunday | Saturday
        var weekdays = Parse("0111110"); // Monday | Tuesday | Wednesday | Thursday | Friday
    }