基类/抽象类中的C#最佳部分接口实现

use*_*528 5 c# refactoring abstract-class interface

.net不允许在基类中实现部分接口.作为缓解措施,我已经提出了3种替代解决方案.请帮我决定哪些在重构,编译/运行时错误,可读性方面更具普遍性.但首先是几条评论.

  • 当然,您可以始终将对象转换为IFoo并在没有任何编译器警告的情况下调用任何方法.但这不符合逻辑,你不会这样做.这种结构不会因重构而发生.
  • 我想要最大限度的分离 直接类契约(公共方法和属性)应该与接口实现分开.我经常使用接口来分隔对象的交互.

我的比较:

  1. BaseClass1/MyClass1的:
    • con:必须在BaseClass1中为每个未实现的IFoo方法创建虚拟抽象.
    • con:附加方法换行 - 在运行时对生产力的影响很小.
  2. BaseClass2/MyClass2:
    • con:如果在MyClass2中没有实现Method2,则没有编译器警告.而是运行时异常.单元测试覆盖率较差的重构可能会破坏代码的稳定性.
    • con:必须添加额外的过时构造以防止来自子类的直接方法调用.
    • con:Method2对于BaseClass1是公共的,因此它现在是类合同的一部分.必须使用"过时"构造来防止直接调用,而不是通过IFoo.
  3. BaseClass3/MyClass3:
    • 亲:(与#2相比).更具可读性.您看到MyClass2.Method2是IFoo实现,而不仅仅是一些覆盖方法.
public interface IFoo
{
    void Method1();
    void Method2();
}
Run Code Online (Sandbox Code Playgroud)
public abstract class BaseClass1 : IFoo
{
    void IFoo.Method1()
    { 
        //some implementation
    }

    void IFoo.Method2()
    {
        IFooMethod2();
    }

    protected abstract void IFooMethod2();
}

public class MyClass1 : BaseClass1
{
    [Obsolete("Prohibited direct call from child classes. only inteface implementation")]
    protected override void IFooMethod2()
    {
        //some implementation
    }
}
Run Code Online (Sandbox Code Playgroud)
public abstract class BaseClass2 : IFoo
{
    void IFoo.Method1()
    {
        //some implementation
    }

    [Obsolete("Prohibited direct call from child classes. only inteface implementation")]
    public virtual void Method2()
    {
        throw new NotSupportedException();
    }
}

public abstract class MyClass2 : BaseClass2
{
    public override void Method2()
    {
        //some implementation
    }
}
Run Code Online (Sandbox Code Playgroud)
public abstract class BaseClass3 : IFoo
{
    void IFoo.Method1()
    {
        //some implementation
    }

    void IFoo.Method2()
    {
        throw new NotSupportedException();
    }
}

public abstract class MyClass3 : BaseClass3, IFoo
{
    void IFoo.Method2()
    {
        //some implementation
    }
}
Run Code Online (Sandbox Code Playgroud)

num*_*rek 9

我喜欢这个版本,基类不能实例化,因为它的抽象,派生类必须在其声明中列出IFoo,否则它将不会实现接口,然后它只负责实现接口的其余部分.我可以看到的一个缺点是你不能在基类中显式实现接口方法(即没有IFoo:Method1),但是否则这是一个相当低的开销版本.

public interface IFoo
{
    void Method1();
    void Method2();
}

public abstract class BaseClass1
{
    public void Method1()
    {
        //some implementation
    }
}

public class MyClass1 : BaseClass1, IFoo
{
    public void Method2()
    {
        //some implementation
    }
}
Run Code Online (Sandbox Code Playgroud)


ole*_*sii 6

设计一个没有实现明确定义的合同的类是非常糟糕的.这是极端的,因为你首先说一个班级能够做某事.你明确地强调了类可以做的事情,但是后来在代码中你说nahh,搞砸了,这个类可以在没有实现的情况下生存.编译器非常明智地要求您实施合同,但由您决定.

这是一些常见的解决方案

解决方案不好

  • 抛出异常(NonImplementedException或NotSupportedException,参见示例)
  • 声明它已过时(从一开始就设计好)

好的解决方案

  • 显式接口实现,但你仍然实现它(只是隐藏它)

最佳方案

  • 使用接口隔离(将胖接口拆分为更薄且更易于管理的接口)


ken*_*n2k 5

好的,您可以尝试以下内容,因为它BaseClass是抽象的:

public interface IFoo
{
    void Method1();

    void Method2();
}

public abstract class BaseClass : IFoo
{
    public void Method1()
    {
        // Common stuff for all BaseClassX classes
    }

    // Abstract method: it ensures IFoo is fully implemented
    // by all classes that inherit from BaseClass, but doesn't provide
    // any implementation right here.
    public abstract void Method2();
}

public class MyClass1 : BaseClass
{
    public override void Method2()
    {
        // Specific stuff for MyClass1
        Console.WriteLine("Class1");
    }
}

public class MyClass2 : BaseClass
{
    public override void Method2()
    {
        // Specific stuff for MyClass2
        Console.WriteLine("Class2");
    }
}

private static void Main(string[] args)
{
    IFoo test1 = new MyClass1();
    IFoo test2 = new MyClass2();

    test1.Method2();
    test2.Method2();

    Console.ReadKey();
}
Run Code Online (Sandbox Code Playgroud)