c# - Nested Switch Statements: Architectural Design Issue -


i'm working on project , task add advanced search , filtering option allows users query desired results list of windows events by specifying many conditions want.

the idea each windows event log has several properties such logname, source, createddate, message, number, etc. (part of fielditem enum). in total, there four possbile data types: string, datetime, integral (int/long), , evententrytype. each of these 4 data types has own collection of selector operands (part of selectoroperator enum). here picture give better idea of how overall structure looks like:

my initial implementation of idea this:

 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 string)).tolist();                             break;                         case selectoroperator.endswith:                             currentlogs = currentlogs.where(item => item.category.tolower().endswith(condition.fieldvalue string)).tolist();                             break;                         case selectoroperator.is:                             currentlogs = currentlogs.where(item => string.equals(item.category, condition.fieldvalue string, stringcomparison.ordinalignorecase)).tolist();                             break;                         case selectoroperator.startswith:                             currentlogs = currentlogs.where(item => item.category.tolower().startswith(condition.fieldvalue string)).tolist();                             break;                     }                     break;                 case fielditem.instanceid:                     switch (condition.selectoroperator)                     {                         case selectoroperator.equals:                             currentlogs = currentlogs.where(item => item.instanceid == long.parse(condition.fieldvalue string)).tolist();                             break;                         case selectoroperator.isgreaterthan:                             currentlogs = currentlogs.where(item => item.instanceid > long.parse(condition.fieldvalue string)).tolist();                             break;                         case selectoroperator.islessthan:                             currentlogs = currentlogs.where(item => item.instanceid < long.parse(condition.fieldvalue string)).tolist();                             break;                     }                     break;                 case fielditem.logname:                     switch (condition.selectoroperator)                     {                         case selectoroperator.contains:                             currentlogs = currentlogs.where(item => item.logname.tolower().contains(condition.fieldvalue string)).tolist();                             break;                         case selectoroperator.endswith:                             currentlogs = currentlogs.where(item => item.logname.tolower().endswith(condition.fieldvalue string)).tolist();                             break;                         case selectoroperator.is:                             currentlogs = currentlogs.where(item => string.equals(item.logname, condition.fieldvalue string, stringcomparison.ordinalignorecase)).tolist();                             break;                         case selectoroperator.startswith:                             currentlogs = currentlogs.where(item => item.logname.tolower().startswith(condition.fieldvalue string)).tolist();                             break;                     }                     break;                 case fielditem.message:                     switch (condition.selectoroperator)                     {                         case selectoroperator.contains:                             currentlogs = currentlogs.where(item => item.message.tolower().contains(condition.fieldvalue string)).tolist();                             break;                         case selectoroperator.endswith:                             currentlogs = currentlogs.where(item => item.message.tolower().endswith(condition.fieldvalue string)).tolist();                             break;                         case selectoroperator.is:                             currentlogs = currentlogs.where(item => string.equals(item.message, condition.fieldvalue string, stringcomparison.ordinalignorecase)).tolist();                             break;                         case selectoroperator.startswith:                             currentlogs = currentlogs.where(item => item.message.tolower().startswith(condition.fieldvalue string)).tolist();                             break;                     }                     break;                 case fielditem.number:                     switch (condition.selectoroperator)                     {                         case selectoroperator.equals:                             currentlogs = currentlogs.where(item => item.number == int.parse(condition.fieldvalue string)).tolist();                             break;                         case selectoroperator.isgreaterthan:                             currentlogs = currentlogs.where(item => item.number > int.parse(condition.fieldvalue string)).tolist();                             break;                         case selectoroperator.islessthan:                             currentlogs = currentlogs.where(item => item.number < int.parse(condition.fieldvalue string)).tolist();                             break;                     }                     break;                 case fielditem.source:                     switch (condition.selectoroperator)                     {                         case selectoroperator.contains:                             currentlogs = currentlogs.where(item => item.source.tolower().contains(condition.fieldvalue string)).tolist();                             break;                         case selectoroperator.endswith:                             currentlogs = currentlogs.where(item => item.source.tolower().endswith(condition.fieldvalue string)).tolist();                             break;                         case selectoroperator.is:                             currentlogs = currentlogs.where(item => string.equals(item.source, condition.fieldvalue string, stringcomparison.ordinalignorecase)).tolist();                             break;                         case selectoroperator.startswith:                             currentlogs = currentlogs.where(item => item.source.tolower().startswith(condition.fieldvalue 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 string)).tolist();                             break;                         case selectoroperator.isnot:                             currentlogs = currentlogs.where(item => item.type != (eventlogentrytype)enum.parse(typeof(eventlogentrytype), condition.fieldvalue string)).tolist();                             break;                     }                     break;             }         }          return currentlogs;     } 

a sample query might this:

condition selector:

all of conditions met 

conditions:

logname "application" message contains "error" type isnot "information" instanceid islessthan 1934 

as can see, searchall() method quite long , not maintainable due nested switch statements. code works, however, feel not elegant way implement design. there better way approach problem? maybe figuring out way reduce complexity of switch hierarchy or making code more generic? help/suggestion appreciated.

i think need 2 switch statements, don't need nested. can separate out operations work generically on kind of object, , pass in object searching on @ runtime.

public static class searchprovider {     static func<object, bool> getsearchmethod(selectoroperator selectoroperator, string conditionfieldvalue)     {         switch (selectoroperator)         {             //strings             case selectoroperator.contains:                 return new func<object, bool>(s => s.tostring().tolower().contains(conditionfieldvalue));             case selectoroperator.startswith:                 return new func<object, bool>(s => s.tostring().tolower().startswith(conditionfieldvalue));             case selectoroperator.endswith:                 return new func<object, bool>(s => s.tostring().tolower().endswith(conditionfieldvalue));             case selectoroperator.is:                 return new func<object, bool>(s => string.equals(s.tostring(), conditionfieldvalue, stringcomparison.ordinalignorecase));              //numbers             case selectoroperator.equals:                 return new func<object, bool>(n => (long)n == long.parse(conditionfieldvalue));             case selectoroperator.isgreaterthan:                 return new func<object, bool>(n => (long)n > long.parse(conditionfieldvalue));             case selectoroperator.islessthan:                 return new func<object, bool>(n => (long)n < long.parse(conditionfieldvalue));              //type             case selectoroperator.typeis:                 return new func<object, bool>(t => (eventlogentrytype)t == (eventlogentrytype)enum.parse(typeof(eventlogentrytype), conditionfieldvalue));             case selectoroperator.typeisnot:                 return new func<object, bool>(t => (eventlogentrytype)t != (eventlogentrytype)enum.parse(typeof(eventlogentrytype), conditionfieldvalue));              default:                 throw new exception("unknown selector operator");         }     }      private static list<eventlogitem> searchall(list<eventlogitem> currentlogs, searchquery query)     {         foreach (searchcondition condition in query.conditions)         {             var search = getsearchmethod(condition.selectoroperator, condition.fieldvalue string);             switch (condition.fieldname)             {                 case fielditem.category:                     currentlogs = currentlogs.where(item => search(item.category)).tolist();                     break;                 case fielditem.instanceid:                     currentlogs = currentlogs.where(item => search(item.instanceid)).tolist();                     break;                 case fielditem.logname:                     currentlogs = currentlogs.where(item => search(item.logname)).tolist();                     break;                 case fielditem.message:                     currentlogs = currentlogs.where(item => search(item.message)).tolist();                     break;                 case fielditem.number:                     currentlogs = currentlogs.where(item => search(item.number)).tolist();                     break;                 case fielditem.source:                     currentlogs = currentlogs.where(item => search(item.source)).tolist();                     break;                 case fielditem.type:                     currentlogs = currentlogs.where(item => search(item.type)).tolist();                     break;             }         }         return currentlogs;     } } 

note posted late because server crashed, went bed :(
hence it's similar @dasblinkenlight's answer.


Comments

Popular posts from this blog

c# - DetailsView in ASP.Net - How to add another column on the side/add a control in each row? -

javascript - firefox memory leak -

Trying to import CSV file to a SQL Server database using asp.net and c# - can't find what I'm missing -