Your outer switch statement has 9 cases (and one default). If you take advantage of polymorphism, you can split this out into 9 classes with no need for some default handler.
Here's some information about switch statements being a "code smell":
- https://sourcemaking.com/refactoring/smells/switch-statements
- http://c2.com/cgi/wiki?SwitchStatementsSmell
- https://stackoverflow.com/questions/4417070/switch-statements-are-bad
Here's what you'd do with your code. First make your class abstract and give it a CompareTo
method that calls child class CompareToField1Equal
if the Field1
s are equal:
abstract class MyClass { public int CompareTo(object obj) { var y = (ListEntry)obj; var result = string.CompareOrdinal(Field1, y.Field1); if (result != 0) { return result; } return this.CompareToField1Equal(y); } protected abstract int CompareToField1Equal(ListEntry y);}
Every class that extends this MyClass
will represent a case in your outer switch statement. These child classes must implement CompareToField1Equal
. Here's a simple example that replaces the second case in your outer switch statement:
class Field1Caption : MyClass { protected override int CompareToField1Equal(ListEntry y) { return -1; }}
That's it. Some of the cases in your outer switch statement have their own switches. Here's an example that replaces your first case:
class None : MyClass { protected override int CompareToField1Equal(ListEntry y) { case TypEnum.None: return string.CompareOrdinal(Field2, y.Field2); case TypEnum.MessageField2Sum: case TypEnum.MessageField2: case TypEnum.MessageField2Caption: case TypEnum.Field1: return -1; case TypEnum.Field3: case TypEnum.Field2Group: case TypEnum.SubGroup: result = string.CompareOrdinal(Field3, y.Field3); if (result != 0) { return result; } return -1; case TypEnum.Field1Caption: return 1; default: throw new ArgumentOutOfRangeException(); }}
Because your outer switch statement has 9 cases (and one default), you'll have 9 classes that extend MyClass
. Note that you don't need a class that handles the default. This is an advantage of using polymorphism in this way. In what situation would your outer switch's default get hit? If you added a FieldX
to your TypEnum
and your Typ
was equal to FieldX
, you'd get to the default
with its lovely ArgumentOutOfRangeException
.
Now try to replicate this situation using my solution. You can't. The only way to have a FieldX
"case" would be to have a FieldX
class that extends MyClass
, but since the CompareToField1Equal
method is marked abstract, your code won't compile until you implement FieldX
's CompareToField1Equal
. This effectively turns a runtime exception into a compiler error. This is a good thing.
My class None
above has a switch statement with 9 cases in it. You can use polymorphism in the same way to replace this switch statement with an abstract class and 9 child classes. This will be a rewrite of the None
class. Again, the first step is to make None
abstract ...:
abstract class None : MyClass { protected sealed override int CompareToField1Equal(ListEntry y) { return this.CompareToField1EqualByType(y); } protected abstract int CompareToField1EqualByType(ListEntry y);}
Here's a child class that replaces the first case:
class NoneNone : None { protected override int CompareToField1EqualByType(ListEntry y) { return string.CompareOrdinal(Field2, y.Field2); }}
Note that I marked the None.CompareToField1Equal method as sealed. This is not necessary, but I don't want grandchildren of MyClass
overriding CompareToField1Equal
. That'd be confusing.
Here's how you'd use this code:
MyClass left = new NoneNone();MyClass right = new Field1Caption();int result = left.CompareTo(right);