如何使我的switch语句更高效

时间:2019-07-15 19:49:11

标签: c# performance linq

我有一个针对多种枚举类型的switch语句,并根据类型检查该类型的枚举是否与提供的日期范围内的时间戳相对应。我使用10个开关,想知道是否有一个查询功能更强大。

是否可以使用selectmany或从linq的何处提高性能?

private Event[] FilterNotifications(Event[] eventResponseItems, DateTime beginDate, DateTime endDate)
{
    var eventList = eventResponseItems.ToList();
    foreach (var eEvent in eventList)
    {
        switch (eEvent.EventType)
        {
            case "RouteStarted":
                if (!InRange(beginDate, endDate, eEvent.EventInfo.RouteInfo.RouteTimestamps.Started))
                    eventList.Remove(eEvent);
                break;

            case "RouteDeparted":
                if (!InRange(beginDate, endDate, eEvent.EventInfo.RouteInfo.RouteTimestamps.Arrived))
                    eventList.Remove(eEvent);
                break;

            case "RouteArrived":
                if (!InRange(beginDate, endDate, eEvent.EventInfo.RouteInfo.RouteTimestamps.Completed))
                    eventList.Remove(eEvent);
                break;

            case "RouteCompleted":
                if (!InRange(beginDate, endDate, eEvent.EventInfo.RouteInfo.RouteTimestamps.Departed))
                    eventList.Remove(eEvent);
                break;

            case "StopArrived":
                if (!InRange(beginDate, endDate, eEvent.EventInfo.StopInfo.ArrivalTimeStamp))
                    eventList.Remove(eEvent);
                break;

            case "StopDeparted":
                if (!InRange(beginDate, endDate, eEvent.EventInfo.StopInfo.DepartureTimeStamp))
                    eventList.Remove(eEvent);
                break;

            case "StopServicing":
                if (!InRange(beginDate, endDate, eEvent.EventInfo.StopInfo.ArrivalTimeStamp))
                    eventList.Remove(eEvent);
                break;

            case "StopCancelled":
                if (!InRange(beginDate, endDate, eEvent.EventInfo.StopInfo.DepartureTimeStamp))
                    eventList.Remove(eEvent);
                break;

            case "RouteStatusChanged":
                if (!InRange(beginDate, endDate, eEvent.EventInfo.StopInfo.ArrivalTimeStamp))
                    eventList.Remove(eEvent);
                break;
        }
    }

    return eventList.ToArray();
}

private bool InRange(DateTime beginTime, DateTime endTime, string timeStamp)
{
    DateTime timeStmp = DateConverter.ToInternal(timeStamp).Value;
    if ( timeStmp >= beginTime)
    {
        if (endTime != new DateTime() && timeStmp <= endTime)
        {
            return true;
        }

        return true;
    }

    return false;
}

3 个答案:

答案 0 :(得分:4)

在您的方法中,实际上并没有太多优化性能的方法,因为它不使用任何复杂的迭代。

从可读性的角度来看,您可以为此使用字典。这也将使您避免使用.Where()来完全实现返回的数组。

您将需要一个稍微复杂的Func<>,如下所示,以便将每个事件的事件信息枚举转换为时间戳字符串。

var RouteControl = new Dictionary<string,Func<Event,string>>()
{
    { "RouteStarted"       , eEvent => eEvent.EventInfo.RouteInfo.RouteTimestamps.Started },
    { "RouteDeparted"      , eEvent => eEvent.EventInfo.RouteInfo.RouteTimestamps.Arrived },
    { "RouteArrived"       , eEvent => eEvent.EventInfo.RouteInfo.RouteTimestamps.Completed },
    { "RouteCompleted"     , eEvent => eEvent.EventInfo.RouteInfo.RouteTimestamps.Departed },
    { "StopArrived"        , eEvent => eEvent.EventInfo.StopInfo.ArrivalTimeStamp },
    { "StopDeparted"       , eEvent => eEvent.EventInfo.StopInfo.DepartureTimeStamp },
    { "StopServicing"      , eEvent => eEvent.EventInfo.StopInfo.ArrivalTimeStamp },
    { "StopCancelled"      , eEvent => eEvent.EventInfo.StopInfo.DepartureTimeStamp },
    { "RouteStatusChanged" , eEvent => eEvent.EventInfo.StopInfo.ArrivalTimeStamp }       
};

return eventResponseItems.Where(eEvent => 
    !RouteControl.ContainsKey(eEvent.EventType) ||
    InRange(beginDate, endDate, RouteControl[eEvent.EventType](eEvent))
).ToArray();

答案 1 :(得分:3)

我会更关注代码的可维护性而不是性能。如果我们只是尝试删除重复的代码,并使其余的代码易于理解,那么我最终将得到这样的结果:

private Event[] FilterNotifications(Event[] eventResponseItems, DateTime beginDate, DateTime endDate)
{
    return eventResponseItems
        .Where(e => InRange(beginDate, endDate, GetEventRouteTimeStampFromEventType(e.EventInfo.RouteInfo.RouteTimestamps, e.EventType)))
        .ToArray();
}

private string GetEventRouteTimeStampFromEventType(RouteTimeStamps routeTimeStamps, string eventType)
{
    switch (eventType)
    {
        case "RouteStarted":
        case "StopCancelled":
            return routeTimestamps.Started;

        case "RouteDeparted":
            return routeTimestamps.Arrived;

        case "RouteArrived":
            return routeTimestamps.Completed;

        case "RouteCompleted":
            return routeTimestamps.Departed;


        case "StopDeparted":
            return routeTimestamps.DepartureTimeStamp;

        case "RouteStatusChanged":
        case "StopServicing":
        case "StopArrived":
            return routeTimestamps.ArrivalTimeStamp;

        default: throw new ArgumentOutOfRangeException();
        }
    }
}

事实上,这也能获得更好的性能(因为您在进行过滤,而不是创建列表并从列表中删除项目)。所以这是一个不错的胜利。

请注意,我已经假设事件类型列表有限,并且如果您看到其他任何内容,则想引发异常(通常在选择switch语句时就是这种情况) 。如果不是这种情况,您可以执行类似返回null的操作,然后相应地调整其余代码。

答案 2 :(得分:2)

List.Remove在O(n)中,因此您的整个循环在O(n ^ 2)中。如果您在迭代仅包含所需元素的第一个列表时填写第二个列表,则可能会提高性能。