C # Avoiding duplicate logic
Suppose I had a base class A, with subclasses B, C and D. I have a class called MyClass that contains an overload for each of them. I want the counter to increment every time one of these methods is called from anywhere other than MyClass. This can be accomplished with a few simple helper methods:
public class MyClass
{
int counter;
public doSomethingExternal(B b) {counter++; doSomething(b);}
public doSomethingExternal(C c) {counter++; doSomething(c);}
public doSomethingExternal(D d) {counter++; doSomething(d);}
private doSomething(B b) {...}
private doSomething(C c) {...}
private doSomething(D d) {...}
}
It really worries me. Isn't there a better way to write these helper methods so that we don't have duplicate logic for each subclass? The solution I present looks something like this:
// Magically, we know which type we are and call the correct doSomething
public doSomethingExternal(A a) {counter++; doSomething(a);}
I think this kind of generalization can be achieved with Reflection, but I've heard that reflection is usually slow and can be tricky to understand. I am curious if there is a more traditional model that I am overlooking that solves this duplicate logic problem.
Well, one way to solve this is to make classes A, B, and C implement an interface. Depending on what the doSomething function is doing, you can do something like this.
public interface IFoo
{
void DoSomething();
}
then you can have one public function in MyClass.
public void doSomethingExternal(IFoo foo)
{
counter++;
foo.DoSomething();
}
Another approach using dynamic
public class MyClass
{
int counter;
public doSomethingExternal(A value) // A is base class
{
counter++;
dynamic dynamicValue = value;
doSomething(dynamicValue); // Correct overload will be used based on actual type
}
private doSomething(B b) {...}
private doSomething(C c) {...}
private doSomething(D d) {...}
}
The remaining argument doSomethingExternal
as a base class will prevent other types from being passed to the method.
It's awkward and can be cleaned up with C # 7.0 and pattern matching, but I'm not there yet.
public interface A { }
public struct B :A { }
public struct C :A { }
public struct D: A { }
public class MyClass
{
int counter;
private void DoSomething(B b) { ... }
private void DoSomething(C c) { ... }
private void DoSomething(D d) { ... }
public void DoSomethingExternal(A arg)
{
if (arg is B)
{
DoSomething((B)arg);
}
else if (arg is C)
{
DoSomething((C)arg);
}
else if (arg is D)
{
DoSomething((D)arg);
}
else
{
// If `A` is not of `B`, `C` or `D` types return without incrementing counter
return;
}
counter++;
}
}
Edit 1
if no generic interface or class A
exists then you should use object
.
public void DoSomethingExternal(object arg)
{
}
It really worries me. Isn't there a better way to write these helper methods so that we don't have duplicate logic for each subclass?
Why? I do find that your code is pretty easy to read. I wouldn't consider "duplicate code" incrementing a simple counter and delegating a private method. Consider all the alternatives posted? Do any of them make your life easier?
Surely you could use C # 7 pattern matching, but is it really worth it?
public void doSomethingExternal(A a)
{
counter++;
switch (a)
{
case B b:
doSomething(b);
break;
case C c:
doSomething(c);
break;
case D d:
doSomething(d);
break;
case null:
throw new ArgumentNullException(nameof(a));
default:
throw new InvalidOperationException();
}
}
Anything just avoid duplication counter++
?
Its your call, we probably only see a very simplified scenario of what your code looks like and the extent of your "duplicated" logic.