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.

+3


source to share


4 answers


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();
}

      

+2


source


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.

+2


source


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)
{
}

      

-1


source


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.

-1


source







All Articles