【问题标题】:Selecting object property with variable?选择带有变量的对象属性?
【发布时间】:2021-04-23 14:11:55
【问题描述】:

我正在使用返回此 JSON 的 API:

"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
    },

现在我可以使用点表示法获得截止时间。

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

但是,我想要的是检查今天是哪一天

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

然后将该变量用作属性名称。

但是,我完全不知道该怎么做。我虽然也许我可以使用括号表示法,但我只是得到一个“无法将 [] 索引应用于截止日期类型的表达式。(截止日期只是一个具有周一至周日时间跨度属性的模型)

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 to get a property value based on the name
  • 如果您将 Deadlines 视为一本字典,而不是为一周中的每一天定义不同的属性,那将会容易得多。 public Dictionary&lt;string, TimeSpan?&gt; Deadlines { get; set; }

标签: c#


【解决方案1】:

好吧,也许您应该使用 Dictionary&lt;DayOfWeek, TimeSpan?&gt; 而不是多个属性。

如果不可能:

高效的方式,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));
        }
    }
}

或者你可以有一个返回截止日期的字典:

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);
}

还有反射,但我不会在这里使用它,因为它效率不高且不可读。

嗯,就是这样:

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);
}

使用您的样品:

string dow = DateTime.Now.DayOfWeek.ToString(); 
IEnumerable<TimeSpan?> deadlines = _api.Select(x => x.Deadlines.GetDeadline(dow));

【讨论】:

  • 非常感谢! switch 语句最适合我 :)
【解决方案2】:

你有两个选择:

  • switch语句

    switch( dayOfWeek )
    {
        case Monday: return deadlines.Monday;
        case Tuesday: return deadlines.Tuesday;
        ...
    }
    
  • 反射。

    这是相当高级的,而且非常hacky,所以我不推荐它。它包括从typeof(DayOfWeek) 获取字段列表,并为每个字段检查该字段的名称是否是您要查找的名称,如果是,则获取该字段的值。我只是为了完整性而提及它,我不建议使用它,因此我将跳过有关如何使用它的确切细节。

【讨论】:

  • 谢谢!根据另一位用户的建议,我首先使用了反射方法(有效),但在阅读了您的评论后,我将其更改为 switch 方法:) 还考虑到我在链接线程中读到使用反射很慢
猜你喜欢
  • 1970-01-01
  • 2014-02-17
  • 2016-12-17
  • 2012-12-07
  • 1970-01-01
  • 1970-01-01
  • 2019-05-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多