简体   繁体   English

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

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

.net does not allow partial interface implementation in base classes. .net不允许在基类中实现部分接口。 As a mitigation I've come to 3 alternate solutions. 作为缓解措施,我已经提出了3种替代解决方案。 Please help me decide which is more universal in terms of refactoring, compile/run time errors, readability. 请帮我决定哪些在重构,编译/运行时错误,可读性方面更具普遍性。 But first a couple of comments. 但首先是几条评论。

  • Of course you may always cast object to IFoo and call any method without any compiler warning. 当然,您可以始终将对象转换为IFoo并在没有任何编译器警告的情况下调用任何方法。 But it's not logical, you wouldn't do that normally. 但这不符合逻辑,你不会这样做。 This construct wouldn't occur as a result of refactoring. 这种结构不会因重构而发生。
  • I want maximum separation. 我想要最大限度的分离 Direct class contract (public methods and properties) should be separated with interface implementations. 直接类契约(公共方法和属性)应该与接口实现分开。 I use interfaces a lot to separate object interations. 我经常使用接口来分隔对象的交互。

My comparison: 我的比较:

  1. BaseClass1/MyClass1: BaseClass1 / MyClass1的:
    • con: Have to create virtual abstract in BaseClass1 for each not implemented method of IFoo. con:必须在BaseClass1中为每个未实现的IFoo方法创建虚拟抽象。
    • con: Additional method wrap - slight productivity impact at runtime. con:附加方法换行 - 在运行时对生产力的影响很小。
  2. BaseClass2/MyClass2: BaseClass2 / MyClass2:
    • con: no compiler warning if no implementation of Method2 in MyClass2. con:如果在MyClass2中没有实现Method2,则没有编译器警告。 Runtime exception instead. 而是运行时异常。 Refactoring with poor unit test coverage may potentially destabilize code. 单元测试覆盖率较差的重构可能会破坏代码的稳定性。
    • con: has to put additional obsolete construct to prevent direct method call from child classes. con:必须添加额外的过时构造以防止来自子类的直接方法调用。
    • con: Method2 is public for BaseClass1 so it's part of class contract now. con:Method2对于BaseClass1是公共的,因此它现在是类合同的一部分。 Have to put "Obsolete" construct to prevent direct call, not via IFoo. 必须使用“过时”构造来防止直接调用,而不是通过IFoo。
  3. BaseClass3/MyClass3: BaseClass3 / MyClass3:
    • pro: (Compared to #2). 亲:(与#2相比)。 More readable. 更具可读性。 You see that MyClass2.Method2 is IFoo implementation, not just some overriden method. 您看到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
    }
}

I like this version, the base class can't be instantiated because its abstract, the derived class must list IFoo in its declaration or else it won't be implementing the interface and then it is solely responsible for implementing the rest of the interface. 我喜欢这个版本,基类不能实例化,因为它的抽象,派生类必须在其声明中列出IFoo,否则它将不会实现接口,然后它只负责实现接口的其余部分。 One drawback I can see is you can't explicitly implement the interface methods in the base class (ie no IFoo:Method1), but otherwise this is a fairly low overhead version. 我可以看到的一个缺点是你不能在基类中显式实现接口方法(即没有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
    }
}

It is extremely bad to design a class that doesn't implement a well-defined contract. 设计一个没有实现明确定义的合同的类是非常糟糕的。 It is extreme because you firstly say that a class is capable of doing something. 这是极端的,因为你首先说一个班级能够做某事。 You explicitly highlight that the class can do stuff, but later in the code you say nahh, screw it, this class can live without implementation. 你明确地强调了类可以做的事情,但是后来在代码中你说nahh,拧紧它,这个类可以在没有实现的情况下生存。 Compiler very wisely asks you to implement the contract, but it is left up to you to decide. 编译器非常明智地要求您实施合同,但由您决定。

Here are some common solutions 这是一些常见的解决方案

Bad solution 解决方案不好

  • Throw an exception (NonImplementedException or NotSupportedException, see sample ) 抛出异常(NonImplementedException或NotSupportedException,参见示例
  • Declare it as obsolete (design it good from the beginning) 声明它已过时(从一开始就设计好)

Better solution 好的解决方案

  • Explicit interface implementation, but you still implement it (just kind of hide it) 显式接口实现,但你仍然实现它(只是隐藏它)

Best solution 最佳方案

  • Use interface segregation (split your fat interface into thinner and more manageable ones) 使用接口隔离(将胖接口拆分为更薄且更易于管理的接口)

Ok, you could try the following as BaseClass is abstract: 好的,您可以尝试以下操作,因为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();
}

I'd suggest having the abstract base class implement the interface with methods that call protected abstract methods, as shown in your first example, except for methods which some derived classes may not implement (following the "throw everything into IList but don't have all the methods actually work" pattern); 我建议让抽象基类使用调用protected abstract方法的方法实现接口,如第一个示例所示,除了某些派生类可能无法实现的方法(在“将所有内容抛入IList但没有所有方法实际上都是“模式”; those could be protected virtual stubs which throw NotSupportedException . 那些可能是protected virtual存根,它会抛出NotSupportedException

Note that it is up to the child class whether to expose any particular member of the interface as a like-named public member (which could call the appropriate abstract member). 请注意,子类是否要将接口的任何特定成员公开为类似命名的公共成员(可以调用适当的抽象成员)。

The proper pattern in VB.net would be something like MustOverride Sub IFoo_Method1() Implements IFoo.Method1 , which would avoid the extra function call overhead, but C# doesn't provide any means of implementing an interface with a protected member. VB.net中的正确模式将类似于MustOverride Sub IFoo_Method1() Implements IFoo.Method1 ,这将避免额外的函数调用开销,但C#不提供任何实现与受保护成员的接口的方法。 Using explicit interface implementation for any method which may have to be overridden in a child class is somewhat icky, because it's impossible for the child's re-implementation of the interface to chain to the parent's implementation. 对于可能必须在子类中重写的任何方法使用显式接口实现有点icky,因为子项的重新实现不可能链接到父实现。

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

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