简体   繁体   English

向从 C# 接口继承的类添加通用方法?

[英]Add common method to classes inheriting from a C# Interface?

I have an interface such as this one:我有一个这样的界面:

    public interface ITestInterface
    {
        int a { get; set; }

        void DoSomething();
    }

Some of my classes are deriving from this interface:我的一些类是从这个接口派生的:

    public class OneClass : ITestInterface
    {
        public int a { get; set; }

        public void DoSomething()
        {
            Console.WriteLine(this.a.ToString());
        }
    }

    public class AnotherClass : ITestInterface
    {
        public int a { get; set; }

        public void DoSomething()
        {
            Console.WriteLine((this.a * 2).ToString());
        }
    }

Since I now need a (large) common method on all classes derived from my interface, I was trying to provide an additional base class for that:由于我现在需要在从我的接口派生的所有类上使用(大型)通用方法,因此我试图为此提供一个额外的基础 class:

 public class MyBaseClass
    {
        public void LargeCommonMethod()
        {
            Console.WriteLine((this.a * 3).ToString()); // no 'a' on base class
        }
    }

This clearly doesn't work because the base class would also need to implement my interface in order to know about that a field.这显然不起作用,因为基础 class 还需要实现我的接口才能了解a字段。

I am now asking myself what the best approach would be here:我现在问自己最好的方法是什么:

  • make MyBaseClass inherit from ITestInterface ?MyBaseClassITestInterface继承?
  • set LargeCommonMethod() to protected and provide all internal data it uses via arguments?LargeCommonMethod()设置为protected并通过 arguments 提供它使用的所有内部数据? (There's actually a lot of these..) (实际上有很多这样的..)
  • skip the interface all along and replace it with an abstract base class?一直跳过接口并用抽象基础 class 替换它?
  • ...? ...?

C# 8 provides a feature precisely for this scenario. C# 8 正好为这种情况提供了一个功能。

  • Your classes all implement an interface你的类都实现了一个接口
  • You want to add a method to the interface你想给接口添加一个方法
  • You don't want a breaking change to all of the existing classes.您不希望对所有现有类进行重大更改。 If you add a method to the interface all of the classes will break unless you find some way to add the method to all of them.如果向接口添加方法,所有类都会中断,除非您找到某种方法将方法添加到所有类。 (That includes modifying them all to inherit from a new base class.) (这包括修改它们以从新的基础 class 继承。)

That feature is default interface methods .该功能是默认接口方法

You can add your method and a default implementation to the interface:您可以将您的方法和默认实现添加到接口:

public interface ITestInterface
{
    int a { get; set; }

    void DoSomething();

    void LargeCommonMethod()
    {
        Console.WriteLine((this.a * 3).ToString());
    }
}

Your existing classes that implement the interface will not break.您现有的实现该接口的类不会中断。 When cast as the interface, you'll be able to call the method which is defined in the interface.当转换为接口时,您将能够调用接口中定义的方法。 You can still modify any class to provide its own implementation, overriding the interface's default implementation.您仍然可以修改任何 class 以提供自己的实现,覆盖接口的默认实现。

For the method to be available the object must be cast as the interface - ITestInterface .要使该方法可用,必须将 object 转换为接口 - ITestInterface

A lot of developers - including myself - found this to be an odd feature.许多开发人员——包括我自己——发现这是一个奇怪的功能。 But this is the scenario it's for.但这是它的场景。

Some documentation 一些文档

The most common scenario is to safely add members to an interface already released and used by innumerable clients.最常见的场景是将成员安全地添加到已被无数客户端发布和使用的接口中。

If you require a base implementation for a method then an interface is clearly not the way to go.如果您需要方法的基本实现,那么接口显然不是 go 的方式。

I would choose an abstract class instead and get rid of the interface.我会选择一个抽象的 class 代替并摆脱接口。 There is no need to complicate the design basically.基本上没有必要使设计复杂化。

The Adapter pattern could fit your Use case, when you want to keep the ITestInterface consistent:当您希望保持 ITestInterface 一致时,适配器模式可能适合您的用例:

public interface ITestInterface
{
    int a { get; set; }

    void DoSomething();
}

public class TestInterfaceAdapter : ITestInterface
{
    private readonly ITestInterface _testInterface;

    public int a {
        get => _testInterface.a;
        set => _testInterface.a = value;
    }

    public TestInterfaceAdapter(ITestInterface testInterface)
    {
        _testInterface = testInterface;
    }

    public void DoSomething()
    {
        _testInterface.DoSomething();
    }

    public void LargeCommonMethod()
    {
        Console.WriteLine((this.a * 3).ToString());
    }
}

public class OneClass : ITestInterface
{
    public int a { get; set; }

    public void DoSomething()
    {
        Console.WriteLine(this.a.ToString());
    }
}

public class AnotherClass : ITestInterface
{
    public int a { get; set; }

    public void DoSomething()
    {
        Console.WriteLine((this.a * 2).ToString());
    }
}

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

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