【问题标题】:Default implementation of a method for C# interfaces?C# 接口方法的默认实现?
【发布时间】:2015-07-31 01:37:29
【问题描述】:

是否可以在 C# 中定义具有默认实现的接口? (这样我们就可以定义一个实现该接口的类,而无需实现该特定的默认方法)。

我知道扩展方法(例如在this link 中解释)。但这不是我的答案,因为具有如下的方法扩展,编译器仍然抱怨在 MyClass 中实现 MyMethod:

public interface IMyInterface
{
    string MyMethod();
}

public static class IMyInterfaceExtens
{
    public static string MyMethod(this IMyInterface someObj)
    {
        return "Default method!";
    }
}

public class MyClass: IMyInterface
{
// I want to have a default implementation of "MyMethod" 
// so that I can skip implementing it here
}

我问这个是因为(至少据我所知)在 Java 中可以做到这一点(参见here)。

PS:有一个带有某种方法的抽象基类也是不是我的答案,因为我们在C#中没有多重继承,它不同于拥有一个接口的默认实现(如果可能!)。

【问题讨论】:

  • Java 最近通过在接口中定义实现重新引入了多重继承,正如您所说。这确实具有讽刺意味,因为 Java 在引入接口方面发挥了重要作用,首先是解决多继承的可怕问题。虽然 C# 还没有这样做,所以单继承(如果你真的必须使用继承)仍然是所有 C# 支持..
  • 这可能会在 C# 8 中发生变化,请参阅GitHub 上的讨论
  • 此功能已经在 c# 的预览版中 - devblogs.microsoft.com/dotnet/…
  • @DavidArno 大多数来自“经典”多重继承的问题是由于共享状态。默认接口实现不会引入任何新状态。

标签: c# oop interface


【解决方案1】:

C# v8 及更高版本也允许在接口中实现具体方法。这将使您的具体实现类在您将来更改正在实现的接口时不会中断。

所以现在这样的事情是可能的:

interface IA
{
    void NotImplementedMethod();
    void M() { WriteLine("IA.M"); } //method definition present in the interface
}

请参考这个 GitHub issue # 288。此外,Mads Torgersen 在this 第 9 频道视频中详细讨论了此功能。

MS Docs - https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/default-interface-methods

【讨论】:

  • 您是否考虑在 C# > v8.一个可能有用的参考:docs.microsoft.com/en-us/dotnet/csharp/whats-new/…
  • 完成。谢谢你的好建议。
  • 谢谢...虽然它仍然说“将在下一个语言版本中成为可能”并且指的是过时的 Github 问题。我更多地考虑更新的措辞和链接。
【解决方案2】:

在 C# 8.0 中是可能的。您可以添加具有默认实现的方法。您必须将目标框架版本更改为最新版本才能使用此功能。

【讨论】:

    【解决方案3】:

    简答:

    不,你不能在接口中编写方法的实现。

    说明:

    接口就像契约一样,所以从它继承的类型必须定义实现,如果你有一个场景你需要一个默认实现的方法,那么你可以让你的类abstract并定义默认实现对于你想要的方法。

    例如:

    public abstract class MyType
    {
        public string MyMethod()
        {
          // some implementation
        }
    
        public abstract string SomeMethodWhichDerivedTypeWillImplement();
    }
    

    现在在 Dervied 类中:

    public class DerivedType : MyType
    {
      // now use the default implemented method here
    }
    

    更新(C# 8 将对此提供支持):

    C# 8 will allow to have default implementation in interfaces

    【讨论】:

      【解决方案4】:

      作为一个新的 C# 程序员,我正在阅读这个主题并想知道下面的代码示例是否有帮助(我什至不知道这是否是正确的方法)。对我来说,它允许我在接口后面编写默认行为。请注意,我使用泛型类型规范来定义(抽象)类。

      namespace InterfaceExample
      {
          public interface IDef
          {
              void FDef();
          }
      
          public interface IImp
          {
              void FImp();
          }
      
          public class AbstractImplementation<T> where T : IImp
          {
              // This class implements default behavior for interface IDef
              public void FAbs(IImp implementation)
              {
                  implementation.FImp();
              }
          }
      
          public class MyImplementation : AbstractImplementation<MyImplementation>, IImp, IDef
          {
              public void FDef()
              {
                  FAbs(this);
              }
              public void FImp()
              {
                  // Called by AbstractImplementation
              }
          }
      
          class Program
          {
              static void Main(string[] args)
              {
                  MyImplementation MyInstance = new MyImplementation();
      
                 MyInstance.FDef();
              }
          }
      }
      

      【讨论】:

        【解决方案5】:

        不是直接的,但是你可以为一个接口定义一个扩展方法,然后像这样实现它

        public interface ITestUser
        {
            int id { get; set; }
            string firstName { get; set; }
            string lastName { get; set; }
        
            string FormattedName();
        }
        
        static class ITestUserHelpers
        {
            public static string FormattedNameDefault(this ITestUser user)
            {
                return user.lastName + ", " + user.firstName;
            }
        }
        
        public class TestUser : ITestUser
        {
            public int id { get; set; }
            public string firstName { get; set; }
            public string lastName { get; set; }
        
            public string FormattedName()
            {
                return this.FormattedNameDefault();
            }
        }
        

        编辑* 扩展方法和您正在实现的方法的名称必须不同,这一点很重要,否则您可能会遇到 stackoverflow。

        【讨论】:

        • 使用扩展方法会使“明显”界面变得混乱。如果您喜欢允许消费者选择“默认”或“标准”实现,那么这是一个好处。普通的静态方法会避免这种影响。但是,它们也会使编辑器插件/“code sn-ps”更加复杂,因为它们需要接口/帮助类的名称。 return &lt;InterfaceName&gt;Defaults.&lt;MethodName&gt;(this);return this.&lt;MethodName&gt;Default(); 之类的东西。
        【解决方案6】:

        我开发游戏,所以我经常希望接口的所有实现都具有通用功能,但同时允许每个实现做自己的事情,就像子类的虚拟/覆盖方法会起作用一样。

        这就是我的做法:

        public class Example
        {
            void Start()
            {
                WallE wallE = new WallE();
                Robocop robocop = new Robocop();
        
                // Calling Move() (from IRobotHelper)
                // First it will execute the shared functionality, as specified in IRobotHelper
                // Then it will execute any implementation-specific functionality,
                // depending on which class called it. In this case, WallE's OnMove().
                wallE.Move(1);
        
                // Now if we call the same Move function on a different implementation of IRobot
                // It will again begin by executing the shared functionality, as specified in IRobotHlper's Move function
                // And then it will proceed to executing Robocop's OnMove(), for Robocop-specific functionality.
                robocop.Move(1);
        
                // The whole concept is similar to inheritence, but for interfaces.
                // This structure offers an - admittedly dirty - way of having some of the benefits of a multiple inheritence scheme in C#, using interfaces.
            }
        
        }
        
        public interface IRobot
        {
            // Fields
            float speed { get; }
            float position { get; set; }
        
            // Implementation specific functions.
            // Similar to an override function.
            void OnMove(float direction);
        }
        
        public static class IRobotHelper
        {
            // Common code for all IRobot implementations. 
            // Similar to the body of a virtual function, only it always gets called.
            public static void Move(this IRobot iRobot, float direction)
            {
                // All robots move based on their speed.
                iRobot.position += iRobot.speed * direction;
        
                // Call the ImplementationSpecific function
                iRobot.OnMove(direction);
            }
        }
        
        // Pro-Guns robot.
        public class Robocop : IRobot
        {
            public float position { get; set; }
        
            public float speed { get; set;}
        
            private void Shoot(float direction) { }
        
            // Robocop also shoots when he moves
            public void OnMove(float direction)
            {
                Shoot(direction);
            }
        }
        
        // Hippie robot.
        public class WallE : IRobot
        {
            public float position { get; set; }
        
            public float speed { get; set; }
        
            // Wall-E is happy just moving around
            public void OnMove(float direction) { }
        }
        

        【讨论】:

        • 我在您的示例中看不到 IRobotHelper 的任何用途。它的目的是什么?
        • @Jazimov - 提议的架构提供了跨接口实现具有通用功能的能力。 IRobotHelper 拥有公共部分,因此每个实现只需要实现特定于实现的部分。在此示例中,如果您有一个 Robocop 或 WallE 类型的对象 r,或任何其他实现 IRobot 的类,并且您调用 r.Move(1),它将首先从 IRobotHelper 调用共享函数 Move(this IRobot),这将依次调用 IRobot 的相应实现的特定于实现的 OnMove(1)。这对你有意义吗?
        • 非常感谢您提供详细的 cmets 和解释。
        • 如果您像我一样想知道,Move() 怎么可能被 IRobot 调用,它被称为 Extension methods
        • @KonstantinosVasileiadis 标准命名为RobotExtensions。当然,这并不重要。
        猜你喜欢
        • 1970-01-01
        • 2014-12-06
        • 2016-06-16
        • 2013-12-23
        • 2014-10-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多