1

I'm using an API which returns this JSON:

"Deadlines": {
        "Monday": "10:00:00",
        "Tuesday": "10:00:00",
        "Wednesday": "10:00:00",
        "Thursday": "10:00:00",
        "Friday": "10:00:00",
        "Saturday": null,
        "Sunday": null
    },

right now I can get a deadline time by using dot notation.

var deadline = _api.Select(x => x.Deadlines.Friday);

However, what I want, is to check which day it is today

var todaysDayOfWeek = DateTime.Now.DayOfWeek.ToString();

and then use that variable as the property name.

However, I have absolutely no idea how to do this. I though that maybe I can use bracket notation, but I just get a "Cannot apply indexing with [] to an expression of type Deadlines. (Deadlines is just a model which has mon-sun timespan properties)

var todaysDayOfWeek = DateTime.Now.DayOfWeek.ToString();
var deadline = _api.Select(x => x.Deadlines[todaysDayOfWeek]); // <-- produces aforementioned error
    public class Deadlines
    {
        public TimeSpan? Monday { get; set; }
        public TimeSpan? Tuesday { get; set; }
        public TimeSpan? Wednesday { get; set; }
        public TimeSpan? Thursday { get; set; }
        public TimeSpan? Friday { get; set; }
        public TimeSpan? Saturday { get; set; }
        public TimeSpan? Sunday { get; set; }
    }

How would one go about achieving this?

jrwebbie
  • 99
  • 1
  • 11
  • Does this answer your question? [How to get a property value based on the name](https://stackoverflow.com/questions/5508050/how-to-get-a-property-value-based-on-the-name) – gunr2171 Apr 23 '21 at 14:12
  • 3
    If you treat Deadlines like it's a dictionary instead of defining a different property for each day of the week, that will be a lot easier. `public Dictionary Deadlines { get; set; }` – mason Apr 23 '21 at 14:15

2 Answers2

2

Well, maybe you should use a Dictionary<DayOfWeek, TimeSpan?> instead of multiple properties.

If that's not possible:

The efficient way, a switch:

public class Deadlines
{
    public TimeSpan? Monday { get; set; }
    public TimeSpan? Tuesday { get; set; }
    public TimeSpan? Wednesday { get; set; }
    public TimeSpan? Thursday { get; set; }
    public TimeSpan? Friday { get; set; }
    public TimeSpan? Saturday { get; set; }
    public TimeSpan? Sunday { get; set; }
    
    public TimeSpan? GetDeadLine(DayOfWeek dow)
    {
        switch(dow)
        {
            case DayOfWeek.Monday:
                return Monday;
            case DayOfWeek.Tuesday:
                return Tuesday;
            case DayOfWeek.Wednesday:
                return Wednesday;
            case DayOfWeek.Thursday:
                return Thursday;
            case DayOfWeek.Friday:
                return Friday;
            case DayOfWeek.Saturday:
                return Saturday;
            case DayOfWeek.Sunday:
                return Sunday;
            default: throw new ArgumentException(nameof(dow));
        }
    }
}

Or you could have a dictionary that returns the deadline:

public class Deadlines
{
    public TimeSpan? Monday { get; set; }
    public TimeSpan? Tuesday { get; set; }
    public TimeSpan? Wednesday { get; set; }
    public TimeSpan? Thursday { get; set; }
    public TimeSpan? Friday { get; set; }
    public TimeSpan? Saturday { get; set; }
    public TimeSpan? Sunday { get; set; }

    private static readonly Dictionary<DayOfWeek, Func<Deadlines, System.TimeSpan?>> DayOfWeekMapper;
    static Deadlines()
    {
        DayOfWeekMapper = new Dictionary<System.DayOfWeek, Func<Deadlines, System.TimeSpan?>>
        {
            { DayOfWeek.Monday, dl => dl.Monday },{ DayOfWeek.Tuesday, dl => dl.Tuesday },{ DayOfWeek.Wednesday, dl => dl.Wednesday },
            { DayOfWeek.Thursday, dl => dl.Thursday },{ DayOfWeek.Friday, dl => dl.Friday },{ DayOfWeek.Saturday, dl => dl.Saturday },{ DayOfWeek.Sunday, dl => dl.Sunday }
        };
    }

    public TimeSpan? GetDeadline(DayOfWeek dow) => DayOfWeekMapper[dow].Invoke(this);
}

There's also reflection but i would not use it here since it's not efficient and not readable.

Well, here it is:

public class Deadlines
{
    public TimeSpan? Monday { get; set; }
    public TimeSpan? Tuesday { get; set; }
    public TimeSpan? Wednesday { get; set; }
    public TimeSpan? Thursday { get; set; }
    public TimeSpan? Friday { get; set; }
    public TimeSpan? Saturday { get; set; }
    public TimeSpan? Sunday { get; set; }

    private static readonly Dictionary<string,PropertyInfo> DayOfWeekPropertyMapper;
    static Deadlines()
    {
        DayOfWeekPropertyMapper = typeof(Deadlines).GetProperties(BindingFlags.Public | BindingFlags.Instance)
            .Where(p => Enum.GetNames(typeof(DayOfWeek)).Contains(p.Name))
            .ToDictionary(p => p.Name, p => p);
    }

    public TimeSpan? GetDeadline(string dayOfWeek) => (TimeSpan?)DayOfWeekPropertyMapper[dayOfWeek].GetValue(this);
}

With your sample:

string dow = DateTime.Now.DayOfWeek.ToString(); 
IEnumerable<TimeSpan?> deadlines = _api.Select(x => x.Deadlines.GetDeadline(dow));
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
1

You have two options:

  • The switch statement

    switch( dayOfWeek )
    {
        case Monday: return deadlines.Monday;
        case Tuesday: return deadlines.Tuesday;
        ...
    }
    
  • Reflection.

    This is quite advanced, and mighty hacky, so I do not recommend it. It consists of getting the list of fields from typeof(DayOfWeek), and for each one of them, checking whether the name of the field is the name you are looking for, and if so, obtaining the value of that field. I am only mentioning it for completeness, I do not recommend using it, therefore I am skipping the exact details on how to do it.

Mike Nakis
  • 56,297
  • 11
  • 110
  • 142
  • Thank you! Based on another user's suggestion, I first used the reflection approach (which worked) but after reading your comment I changed it to the switch approach instead :) also considering that I read in the linked thread that using reflection is slow – jrwebbie Apr 25 '21 at 11:42