我有一个针对多种枚举类型的 switch 语句,我根据类型检查与该类型对应的时间戳是否在提供的日期范围内。我使用了 10 个开关,想知道是否有性能更高的查询函数。
是否可以使用 selectmany 或 linq 中的 where 来使其性能更高?
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;
}
在您的方法中,实际上没有太多可以优化性能的,因为它不使用任何复杂的迭代。
从可读性的角度来看,您可以使用字典。这也将允许您通过使用 .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();
我更关心代码的可维护性而不是性能。如果我们一开始只是尝试删除重复的代码,并使剩余的代码易于理解,我最终会得到这样的结果:
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 之类的操作,并相应地调整剩余的代码。
List.Remove 在 O(n( 中,所以整个循环都在 O(n^2( 中。如果在循环访问仅包含所需元素的第一个列表时填充第二个列表,则可以提高性能。