-2

我用asp.net mvc 3.情况:

我有模型类“事件”

public class Event 
{
    public string Name { get; set; }
    public Period Plan { get; set; }
    public Period Fact { get; set; }
}

public class Period
{
    public bool isPeriod { get; set; }
    public DateTime From { get; set; }
    public DateTime To { get; set; }
}

和控制器中的 ActionResult 方法“示例”。在这种方法中,我有 list<Event> 集合,我需要从 list<Event> 获取字典<DateTime, int>。DateTime - 某个日期,int - 此日期的事件数。事件可以持续几天(isPeriod=1)或仅持续一天(isPeriod=0)。事件的日期也有一些限制,应该添加(dateFrom,dateTo)。

我写了一些代码,适用于这种情况,但看起来不太好。代码的某些部分重复了很多次。可以做些什么来优化这部分代码?也许这里可以使用 LINQ 或其他东西以更简单的方式获得结果?

public ActionResult Example()
{
    List<Event> events = new List<Event>();

    ...

    Dictionary<DateTime, int> days = new Dictionary<DateTime, int>();   //Dictionary which I need in result 

    Dictionary<DateTime, HashSet<string>> dic = new Dictionary<DateTime, HashSet<string>>();    //this dictionary is used in foreach cycle

    foreach (var ev in events)
    {
        //plan
        //exact date
        if (!ev.Plan.isPeriod)
        {

            if (ev.Plan.From >= dateFrom && ev.Plan.From <= dateTo)
            {
                if (!dic.ContainsKey(ev.Plan.From))
                {
                    dic.Add(ev.Plan.From, new HashSet<string>());
                    dic[ev.Plan.From].Add(ev.Key.ToString());
                }
                else
                {
                    dic[ev.Plan.From].Add(ev.Key.ToString());
                }
            }
        }
        //period
        else
        {
            //period is between dateFrom and dateTo
            if (ev.Plan.From >= dateFrom && ev.Plan.To <= dateTo)
            {
                for (DateTime date = ev.Plan.From; date <= ev.Plan.To; date = date.AddDays(1.0))
                {
                    if (!dic.ContainsKey(date))
                    {
                        dic.Add(date, new HashSet<string>());
                        dic[date].Add(ev.Key.ToString());
                    }
                    else
                    {
                        dic[date].Add(ev.Key.ToString());
                    }
                }
            }
            //period begins before dateFrom
            else if (ev.Plan.From < dateFrom && ev.Plan.To <= dateTo)
            {
                for (DateTime date = dateFrom; date <= ev.Plan.To; date = date.AddDays(1.0))
                {
                    if (!dic.ContainsKey(date))
                    {
                        dic.Add(date, new HashSet<string>());
                        dic[date].Add(ev.Key.ToString());
                    }
                    else
                    {
                        dic[date].Add(ev.Key.ToString());
                    }
                }
            }
            //period ends after dateTo
            else if (ev.Plan.From >= dateFrom && ev.Plan.To > dateTo)
            {
                for (DateTime date = ev.Plan.From; date <= dateTo; date = date.AddDays(1.0))
                {
                    if (!dic.ContainsKey(date))
                    {
                        dic.Add(date, new HashSet<string>());
                        dic[date].Add(ev.Key.ToString());
                    }
                    else
                    {
                        dic[date].Add(ev.Key.ToString());
                    }
                }
            }
        }

        //fact
        //exact date
        if (!ev.Fact.isPeriod)
        {
            if (ev.Fact.From >= dateFrom && ev.Fact.From <= dateTo)
            {
                if (!dic.ContainsKey(ev.Fact.From))
                {
                    dic.Add(ev.Fact.From, new HashSet<string>());
                    dic[ev.Fact.From].Add(ev.Key.ToString());
                }
                else
                {
                    dic[ev.Fact.From].Add(ev.Key.ToString());
                }
            }
        }
        //period 
        else
        {
            //period is between dateFrom and dateTo
            if (ev.Fact.From >= dateFrom && ev.Fact.To <= dateTo)
            {
                for (DateTime date = ev.Fact.From; date <= ev.Fact.To; date = date.AddDays(1.0))
                {
                    if (!dic.ContainsKey(date))
                    {
                        dic.Add(date, new HashSet<string>());
                        dic[date].Add(ev.Key.ToString());
                    }
                    else
                    {
                        dic[date].Add(ev.Key.ToString());
                    }
                }
            }
            //period begins before dateFrom
            else if (ev.Fact.From < dateFrom && ev.Fact.To <= dateTo)
            {
                for (DateTime date = dateFrom; date <= ev.Fact.To; date = date.AddDays(1.0))
                {
                    if (!dic.ContainsKey(date))
                    {
                        dic.Add(date, new HashSet<string>());
                        dic[date].Add(ev.Key.ToString());
                    }
                    else
                    {
                        dic[date].Add(ev.Key.ToString());
                    }
                }
            }
            //period ends after dateTo
            else if (ev.Fact.From >= dateFrom && ev.Fact.To > dateTo)
            {
                for (DateTime date = ev.Fact.From; date <= dateTo; date = date.AddDays(1.0))
                {
                    if (!dic.ContainsKey(date))
                    {
                        dic.Add(date, new HashSet<string>());
                        dic[date].Add(ev.Key.ToString());
                    }
                    else
                    {
                        dic[date].Add(ev.Key.ToString());
                    }
                }
            }
        }
        //getting result Dictionary
        foreach (var d in dic)
        {
            days.EventsCount[d.Key] = d.Value.Count();
        }
    }

    return View(days);
}
4

3 回答 3

3

我看到的第一件事......将以下代码取出到一个单独的方法中。

          if (!dic.ContainsKey(date))
            {
                dic.Add(date, new HashSet<string>());
                dic[date].Add(ev.Key.ToString());
            }
            else
            {
                dic[date].Add(ev.Key.ToString());
            }
于 2013-09-10T19:16:13.033 回答
3

你需要用伪代码写下你想要做的事情。这太复杂了。我建议将很多逻辑移到Event类中,可能创建类的两个子Event类来处理这种isPeriod情况。

总之,您需要提取方法,并执行“用子类替换类型代码”重构(在您的情况下,“类型代码”是isPeriod属性)。

(参见例如http://sourcemaking.com/refactoring/replace-type-code-with-subclasses

于 2013-09-10T19:18:55.283 回答
1

您应该将此代码提取到 中testable unit,针对该代码编写单元测试,然后开始重构和优化安全,因为您知道您的测试将捕获您无意中破坏的任何内容。

单元测试的艺术是一个很好的资源。

《原则与模式》也是一本重构的好书,前几章经历了重构场景。

于 2013-09-10T19:22:26.937 回答