C#避免重复逻辑

C#避免重复逻辑,c#,C#,假设我有一个基类a,包含子类B、C和D。我有一个类MyClass,其中每个类都包含一个重载。我想要一个计数器,在从MyClass内部以外的任何地方调用这些方法时递增。这可以通过几个简单的辅助方法来实现: public class MyClass { int counter; public doSomethingExternal(B b) {counter++; doSomething(b);} public doSomethingExternal(C c) {counter+

假设我有一个基类a,包含子类B、C和D。我有一个类MyClass,其中每个类都包含一个重载。我想要一个计数器,在从MyClass内部以外的任何地方调用这些方法时递增。这可以通过几个简单的辅助方法来实现:

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) {...}
}
这真的让我心里很不舒服。有没有更好的方法来编写这些helper方法,这样我们就不会对每个子类都有重复的逻辑?我设想的解决方案类似于:

// Magically, we know which type we are and call the correct doSomething
public doSomethingExternal(A a) {counter++; doSomething(a);} 

我认为这种泛化可以通过反射来完成,但我听说反射通常是缓慢的,并且可能很难理解。我很好奇是否有一种我忽略的更传统的模式可以解决这个逻辑复制问题。

解决这个问题的一种方法是让类a、B和C实现一个接口。根据doSomething函数的作用,您可以执行类似的操作

public interface IFoo
{
   void DoSomething();
}
然后在MyClass中可以有一个公共函数

public void doSomethingExternal(IFoo foo)
{
   counter++;
   foo.DoSomething();
}

另一种方法是使用
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) {...}
}

doSomethingExternal
的参数保留为基类,将阻止将其他类型传递给该方法。

这很笨拙,可以用C#7.0和模式匹配来清理,但我还没有

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++;
    }
}
编辑1

如果公共接口或类
a
不存在,则必须使用
object

public void DoSomethingExternal(object arg)
{
}
这真的让我心里很不舒服。有没有更好的方法来编写这些helper方法,这样我们就不会对每个子类都有重复的逻辑

为什么??我发现你的代码很容易阅读。我不会真正考虑“重复代码”,增加一个简单的计数器并委派给一个私有方法。考虑所有的替代品吗?有没有让你的生活更轻松

当然你可以利用c#7的模式匹配,但这真的值得吗

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();
    }
}
所有这些都是为了避免重复
计数器+++


这是你的要求,我们可能只看到一个非常简单的场景,即你的代码的真实外观和“重复”逻辑的范围。

这将把
MyClass
的主要职责(处理a、B、C类)转移到
a
B
C
。如果
MyClass
不执行其他操作,则根本不需要
MyClass
。不完全是因为MyClass有状态,计数器。根据doSomething方法所做的工作,他可以使用foo.doSomething()并将MyClass发送到方法中(如果他愿意)。可能会对您有所帮助。如果
A
B
C
共享一些共同点,这将非常有用,就像一个接口。我认为
C#
7.0有模式匹配功能,可以帮助您选择正确的调用方法。您在示例中没有使用
模式匹配。模式匹配将检查“模式”并提供结果实例,因此您的
if
语句应该如下所示:
if(arg是B argB){DoSomething(argB);}
@Fabio因为我还没有2017年,所以我无法提供示例。我希望其他人会用C#7.0给出答案