我正在开发一个项目,我的任务是添加一个高级搜索和筛选选项,允许用户通过指定尽可能多的条件从一系列Windows事件列表中查询所需结果如他们想要的。嵌套开关语句:建筑设计问题
的想法是每Windows事件日志具有几个特性,例如LogName
,Source
,CreatedDate
,Message
,Number
,等等(FieldItem枚举的一部分)。总共有四个 possbile数据类型:String
,DateTime
,Integral (Int/Long)
和EventEntryType
。这四种数据类型中的每一种都有自己的选择器操作数集合(SelectorOperator enum的一部分)。这里是一个图片给你的整体结构看起来像一个更好的主意:
我的初步实施这个想法是这样的:
public static class SearchProvider
{
public static List<EventLogItem> SearchInLogs(List<EventLogItem> currentLogs, SearchQuery query)
{
switch (query.JoinType)
{
case ConditionJoinType.All:
return SearchAll(currentLogs, query);
case ConditionJoinType.Any:
return SearchAny(currentLogs, query);
default:
return null;
}
}
private static List<EventLogItem> SearchAll(List<EventLogItem> currentLogs, SearchQuery query)
{
foreach (SearchCondition condition in query.Conditions)
{
switch (condition.FieldName)
{
case FieldItem.Category:
switch (condition.SelectorOperator)
{
case SelectorOperator.Contains:
currentLogs = currentLogs.Where(item => item.Category.ToLower().Contains(condition.FieldValue as string)).ToList();
break;
case SelectorOperator.EndsWith:
currentLogs = currentLogs.Where(item => item.Category.ToLower().EndsWith(condition.FieldValue as string)).ToList();
break;
case SelectorOperator.Is:
currentLogs = currentLogs.Where(item => string.Equals(item.Category, condition.FieldValue as string, StringComparison.OrdinalIgnoreCase)).ToList();
break;
case SelectorOperator.StartsWith:
currentLogs = currentLogs.Where(item => item.Category.ToLower().StartsWith(condition.FieldValue as string)).ToList();
break;
}
break;
case FieldItem.InstanceID:
switch (condition.SelectorOperator)
{
case SelectorOperator.Equals:
currentLogs = currentLogs.Where(item => item.InstanceID == long.Parse(condition.FieldValue as string)).ToList();
break;
case SelectorOperator.IsGreaterThan:
currentLogs = currentLogs.Where(item => item.InstanceID > long.Parse(condition.FieldValue as string)).ToList();
break;
case SelectorOperator.IsLessThan:
currentLogs = currentLogs.Where(item => item.InstanceID < long.Parse(condition.FieldValue as string)).ToList();
break;
}
break;
case FieldItem.LogName:
switch (condition.SelectorOperator)
{
case SelectorOperator.Contains:
currentLogs = currentLogs.Where(item => item.LogName.ToLower().Contains(condition.FieldValue as string)).ToList();
break;
case SelectorOperator.EndsWith:
currentLogs = currentLogs.Where(item => item.LogName.ToLower().EndsWith(condition.FieldValue as string)).ToList();
break;
case SelectorOperator.Is:
currentLogs = currentLogs.Where(item => string.Equals(item.LogName, condition.FieldValue as string, StringComparison.OrdinalIgnoreCase)).ToList();
break;
case SelectorOperator.StartsWith:
currentLogs = currentLogs.Where(item => item.LogName.ToLower().StartsWith(condition.FieldValue as string)).ToList();
break;
}
break;
case FieldItem.Message:
switch (condition.SelectorOperator)
{
case SelectorOperator.Contains:
currentLogs = currentLogs.Where(item => item.Message.ToLower().Contains(condition.FieldValue as string)).ToList();
break;
case SelectorOperator.EndsWith:
currentLogs = currentLogs.Where(item => item.Message.ToLower().EndsWith(condition.FieldValue as string)).ToList();
break;
case SelectorOperator.Is:
currentLogs = currentLogs.Where(item => string.Equals(item.Message, condition.FieldValue as string, StringComparison.OrdinalIgnoreCase)).ToList();
break;
case SelectorOperator.StartsWith:
currentLogs = currentLogs.Where(item => item.Message.ToLower().StartsWith(condition.FieldValue as string)).ToList();
break;
}
break;
case FieldItem.Number:
switch (condition.SelectorOperator)
{
case SelectorOperator.Equals:
currentLogs = currentLogs.Where(item => item.Number == int.Parse(condition.FieldValue as string)).ToList();
break;
case SelectorOperator.IsGreaterThan:
currentLogs = currentLogs.Where(item => item.Number > int.Parse(condition.FieldValue as string)).ToList();
break;
case SelectorOperator.IsLessThan:
currentLogs = currentLogs.Where(item => item.Number < int.Parse(condition.FieldValue as string)).ToList();
break;
}
break;
case FieldItem.Source:
switch (condition.SelectorOperator)
{
case SelectorOperator.Contains:
currentLogs = currentLogs.Where(item => item.Source.ToLower().Contains(condition.FieldValue as string)).ToList();
break;
case SelectorOperator.EndsWith:
currentLogs = currentLogs.Where(item => item.Source.ToLower().EndsWith(condition.FieldValue as string)).ToList();
break;
case SelectorOperator.Is:
currentLogs = currentLogs.Where(item => string.Equals(item.Source, condition.FieldValue as string, StringComparison.OrdinalIgnoreCase)).ToList();
break;
case SelectorOperator.StartsWith:
currentLogs = currentLogs.Where(item => item.Source.ToLower().StartsWith(condition.FieldValue as string)).ToList();
break;
}
break;
case FieldItem.Type:
switch (condition.SelectorOperator)
{
case SelectorOperator.Is:
currentLogs = currentLogs.Where(item => item.Type == (EventLogEntryType)Enum.Parse(typeof(EventLogEntryType), condition.FieldValue as string)).ToList();
break;
case SelectorOperator.IsNot:
currentLogs = currentLogs.Where(item => item.Type != (EventLogEntryType)Enum.Parse(typeof(EventLogEntryType), condition.FieldValue as string)).ToList();
break;
}
break;
}
}
return currentLogs;
}
示例查询可能是这样的:
条件选择:
All of the conditions are met
条件:
LogName Is "Application"
Message Contains "error"
Type IsNot "Information"
InstanceID IsLessThan 1934
正如你所看到的,SearchAll()
方法是很长,不是很维护,由于嵌套switch
语句。但是,代码起作用,我觉得这不是实现这种设计的最优雅的方式。有没有更好的方法来解决这个问题?也许通过找出一种方法来降低switch
层级的复杂性,或者通过使代码更通用?任何帮助/建议表示赞赏。
IMO,看起来像多派遣(访客模式)的候选人。我会给人比我聪明的答案:) – 2013-05-13 21:25:28
什么是您的数据访问策略?如果您使用的是LINQ to SQL或LINQ to Entities,那么通过使用'IQueryable''接口,这可以变得非常简单(也很优雅)。 –
Yuck
2013-05-13 21:30:41
@Yuck事件日志由'System.Diagnostics.EventLog.GetEventLogs()'返回,并从这些列表中创建'EventLogItem'(自定义类型)列表,并最终绑定到'ListView'控件。 'IQueryable'就是我对它的一种预感,但不知道如何实现/使用它。 – PoweredByOrange 2013-05-13 21:37:11