繁体   English   中英

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

[英]C# best partial interface implementation in base/abstract class

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

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

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

这是一些常见的解决方案

解决方案不好

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

好的解决方案

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

最佳方案

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

好的,您可以尝试以下操作,因为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();
}

我建议让抽象基类使用调用protected abstract方法的方法实现接口,如第一个示例所示,除了某些派生类可能无法实现的方法(在“将所有内容抛入IList但没有所有方法实际上都是“模式”; 那些可能是protected virtual存根,它会抛出NotSupportedException

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM