簡體   English   中英

C# class 可以從自己的實現中調用接口的默認接口方法嗎?

[英]Can a C# class call an interface's default interface method from its own implementation?

如果我有這樣的默認接口方法:

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!!

實際上,從實現 class 調用 C# 接口默認方法表明我可以調用我的 class未實現的方法,但正如預期的那樣,添加對((IGreeter)this).SayHello(name); HappyGreeter.SaysHello內部會導致堆棧溢出。

據我所知,您不能在繼承 class 時調用默認接口方法實現(盡管有建議)。 但是你可以從繼承接口調用它:

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!!");
    }
} 

我知道這不是問題的答案,但下一種方法也可用於模擬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!!");
    }
}

有一個非常簡單的方法來處理這個:

  1. 將默認方法聲明為 static。 別擔心,您仍然可以在繼承自它的 class 中覆蓋它。
  2. 在調用 class 的 static 方法時,使用相同類型的語法調用默認方法,只需將接口名稱替換為 class 名稱即可。

此代碼適用於 C#8 或更高版本,如果針對 .NET 框架構建,它將不起作用。 我用 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");
   }
}

示例 Output:

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!!

Static 字段現在也允許在接口中,如本示例所示。

如果由於某種原因您不能使用 static 接口方法,那么您始終可以依賴以下技術:

  1. 將默認方法實現代碼放入單獨的 static 方法中。
  2. 從默認實現方法中調用此 static 方法。
  3. 在接口方法的 class 實現的頂部調用此 static 方法。

例子:

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");
   }
}

樣品 Output:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM