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

C#基类/抽象类中的最佳部分接口实现,c#,interface,refactoring,abstract-class,C#,Interface,Refactoring,Abstract Class,.net不允许在基类中实现部分接口。作为缓解措施,我提出了3种备选解决方案。请帮助我决定哪一个在重构、编译/运行时错误、可读性方面更通用。 但首先是一些评论 当然,您可以始终将对象强制转换为IFoo,并在没有任何编译器警告的情况下调用任何方法。但这不符合逻辑,你通常不会这么做。重构不会产生这种构造 我想要最大限度的分离。直接类契约(公共方法和属性)应该与接口实现分离。我经常使用接口来分离对象交互 我的比较: 基本类1/MyClass1: 缺点:必须为每个未实现的IFoo方法在BaseCla

.net不允许在基类中实现部分接口。作为缓解措施,我提出了3种备选解决方案。请帮助我决定哪一个在重构、编译/运行时错误、可读性方面更通用。 但首先是一些评论

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

  • 基本类1/MyClass1:
    • 缺点:必须为每个未实现的IFoo方法在BaseClass1中创建虚拟抽象
    • 缺点:额外的方法包装-在运行时对生产力有轻微影响
  • BaseClass2/MyClass2:
    • con:如果MyClass2中没有Method2的实现,则没有编译器警告。而不是运行时异常。单元测试覆盖率低的重构可能会破坏代码的稳定性
    • 缺点:必须添加额外的过时构造,以防止子类直接调用方法
    • 缺点:Method2对于BaseClass1是公共的,所以它现在是类契约的一部分。必须使用“过时”构造来防止直接调用,而不是通过IFoo
  • BaseClass3/MyClass3:
    • 赞成:(与#2)相比)。更具可读性。您可以看到MyClass2.Method2是IFoo实现,而不仅仅是一些重写的方法
  • 公共接口IFoo
    {
    void方法1();
    void方法2();
    }
    
    公共抽象类BaseClass1:IFoo
    {
    void IFoo.Method1()
    { 
    //一些实现
    }
    void IFoo.Method2()
    {
    IFooMethod2();
    }
    受保护的抽象void IFooMethod2();
    }
    公共类MyClass1:BaseClass1
    {
    [过时(“禁止子类直接调用。仅限接口实现”)]
    受保护的覆盖无效IFooMethod2()
    {
    //一些实现
    }
    }
    
    公共抽象类BaseClass2:IFoo
    {
    void IFoo.Method1()
    {
    //一些实现
    }
    [过时(“禁止子类直接调用。仅限接口实现”)]
    公共虚拟无效方法2()
    {
    抛出新的NotSupportedException();
    }
    }
    公共抽象类MyClass2:BaseClass2
    {
    公共覆盖无效方法2()
    {
    //一些实现
    }
    }
    
    公共抽象类BaseClass3:IFoo
    {
    void IFoo.Method1()
    {
    //一些实现
    }
    void IFoo.Method2()
    {
    抛出新的NotSupportedException();
    }
    }
    公共抽象类MyClass3:BaseClass3,IFoo
    {
    void IFoo.Method2()
    {
    //一些实现
    }
    }
    
    好的,您可以尝试以下操作,因为
    基类是抽象的:

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

    设计一个没有实现定义良好的契约的类是非常糟糕的。这是极端的,因为你首先说一个类能够做一些事情。您明确强调类可以做的事情,但是稍后在代码中您会说,不,去它的,这个类可以在没有实现的情况下生存。编译器非常明智地要求您执行合同,但这由您决定

    以下是一些常见的解决方案

    糟糕的解决方案

    • 引发异常(NonImplementedException或NotSupportedException,请参阅)
    • 宣布它过时(从一开始就设计好)
    更好的解决方案

    • 显式接口实现,但您仍然实现它(只是有点隐藏它)
    最佳解决方案

    • 使用界面分离(将fat界面拆分为更薄、更易于管理的界面)

    我建议让抽象基类实现与调用
    受保护的抽象
    方法的方法的接口,如第一个示例所示,但某些派生类可能无法实现的方法除外(遵循“将所有内容都放入
    IList
    但并非所有方法都能实际工作”模式);这些可以是
    受保护的虚拟
    存根,它们抛出
    不支持异常

    注意,是否将接口的任何特定成员公开为类似命名的公共成员(可以调用适当的抽象成员)取决于子类


    VB.net中合适的模式类似于
    MustOverride Sub IFoo_Method1()实现IFoo.Method1
    ,这将避免额外的函数调用开销,但C#不提供任何方法来实现具有受保护成员的接口。对可能必须在子类中重写的任何方法使用显式接口实现有点令人讨厌,因为子类的接口重新实现不可能链接到父类的实现。

    我喜欢这个版本,基类不能实例化,因为它的抽象,派生类必须在其声明中列出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
        }
    }
    

    这是一个非常尴尬的模式,你正试图实现。你说过“.NET不允许在基类中实现部分接口。”-这是有原因的。客户机代码需要一些实现接口的东西,你知道,也许。。。实现接口。当然,为不受支持的方法抛出异常是非常糟糕的代码味道…同意这个说法。如果你有一个类型为
    IFoo
    的变量,你真的需要