C#类可以从其自己的实现中调用接口的默认接口方法吗?

时间:2020-06-11 21:57:30

标签: c# c#-8.0 default-interface-member

如果我有这样的默认接口方法:

public interface IGreeter
{
    void SayHello(string name) => System.Console.WriteLine($"Hello {name}!");
}

我可以让我的具体实现调用该默认方法吗?

public class HappyGreeter : IGreeter
{
    public void SayHello(string name)
    {
        // what can I put here to call the default method?
        System.Console.WriteLine("I hope you're doing great!!");
    }
}

这样打电话:

var greeter = new HappyGreeter() as IGreeter;
greeter.SayHello("Pippy");

结果:

// Hello Pippy!
// I hope you're doing great!!

确实Calling C# interface default method from implementing class表明我可以调用类未实现的方法,但是正如预期的那样,在((IGreeter)this).SayHello(name);内向HappyGreeter.SaysHello添加调用会导致堆栈溢出

3 个答案:

答案 0 :(得分:4)

据我所知,您不能在继承类中调用默认接口方法实现(尽管有proposals)。但是您可以从继承接口调用它:

public class HappyGreeter : IGreeter
{
    private interface IWorkAround : IGreeter
    {
        public void SayHello(string name)
        {
            (this as IGreeter).SayHello(name);
            System.Console.WriteLine("I hope you're doing great!!");
        }
    }

    private class WorkAround : IWorkAround {}

    public void SayHello(string name)
    {
        ((IWorkAround)new WorkAround()).SayHello(name);
    }
}

UPD

在我的原始答案中,太多的事情想表明您可以在继承接口中调用base,但是正如@Alexei Levenkov在这种特殊情况下以注释更简洁的方式建议的那样,是这样的:

public class HappyGreeter : IGreeter
{
    private class WorkAround : IGreeter { }
    private static readonly IGreeter _workAround = new WorkAround();

    public void SayHello(string name)
    {
        _workAround.SayHello(name);
        System.Console.WriteLine("I hope you're doing great!!");
    }
} 

答案 1 :(得分:1)

我知道这不是问题的答案,但是下一种方法也可以用来模拟base的功能:

public interface IGreeter
{
    void SayHello(string name) => BaseSayHello(name);

    // This static method can be used in implementers of "IGreeter"
    // to emulate "base" functionality.
    protected static void BaseSayHello(string name) => System.Console.WriteLine($"Hello {name}!");
}

public class HappyGreeter : IGreeter
{
    public void SayHello(string name)
    {
        IGreeter.BaseSayHello(name);
        Console.WriteLine("I hope you're doing great!!");
    }
}

答案 2 :(得分:0)

有一个非常简单的方法来处理这个:

  1. 将默认方法声明为静态方法。不用担心,您仍然可以在继承自它的类中覆盖它。
  2. 调用类的静态方法时,使用相同类型的语法调用默认方法,只用接口名替换类名。

此代码适用于 C#8 或更高版本,如果针对 .NET Framework 构建,它将不起作用。我使用 C#9 在 Windows 10 上运行它,在 .NET 6 上运行,预览版 5。

示例:

public interface IGreeter
{
   private static int DisplayCount = 0;
   public static void SayHello(string name)
   {
      DisplayCount++;
      Console.WriteLine($"Hello {name}! This method has been called {DisplayCount} times.");
   }
}

public class HappyGreeter : IGreeter
{
   public void SayHello(string name)
   {
      // what can I put here to call the default method?
      IGreeter.SayHello(name);
      Console.WriteLine("I hope you're doing great!!");
   }
}

public class CS8NewFeatures
{
   // This class holds the code for the new C# 8 features.
   //
   public void RunTests()
   {
      TestGreeting();
   }

   private void TestGreeting()
   {
      // Tests if a default method may be called after a class has implemented it.
      //
      var hg = new HappyGreeter();
      hg.SayHello("Pippy");
      hg.SayHello("Bob");
      hg.SayHello("Becky");
   }
}

示例输出:

Hello Pippy! This method has been called 1 times.
I hope you're doing great!!
Hello Bob! This method has been called 2 times.
I hope you're doing great!!
Hello Becky! This method has been called 3 times.
I hope you're doing great!!

现在也允许在接口中使用静态字段,如本示例所示。

如果您由于某种原因不能使用静态接口方法,那么您始终可以依靠以下技术:

  1. 将默认方法实现代码放入单独的静态方法中。
  2. 从默认实现方法调用这个静态方法。
  3. 在接口方法的类实现的顶部调用这个静态方法。

示例:

public class DefaultMethods
{
   // This class is used to show that a static method may be called by a default interface method.
   //
   public static void SayHello(string name) => Console.WriteLine($"Hello {name}!");
}

public interface IGreeter
{
   void SayHello(string name) => DefaultMethods.SayHello(name);
}

public class HappyGreeter : IGreeter
{
   public void SayHello(string name)
   {
      // what can I put here to call the default method?
      DefaultMethods.SayHello(name);
      Console.WriteLine("I hope you're doing great!!");
   }
}

public class CS8NewFeatures
{
   // This class holds the code for the new C# 8 features.
   //
   public void RunTests()
   {
      TestGreeting();
   }

   private void TestGreeting()
   {
      // Tests if a default method may be called after a class has implemented it.
      //
      var hg = new HappyGreeter();
      hg.SayHello("Bob");
   }
}

样本输出:

Hello Bob!
I hope you're doing great!!