簡體   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