如何定义必须由 class 的实例实现的函数的签名?

How do I define the signature of a function that must be implemented by instances of a class?

假设我有 class Book:

public class Book{
   public string Title {get; set;}
}

我希望每本书都有一个 Read 函数,该函数 returns 一个字符串并接受页码 - 但每本书的内部结构都会不同(我知道这个例子很糟糕)。如何定义必须由此 class?

的实例实现的函数的签名

像这样:

public class Book{ // need to make this abstract?
   public string Title {get; set;}
   public abstract string Read(int pageNum);
}

// I want to define instances that define their own behavior...
public static Book It => new Book(){ // can't create instance of abstract...
   Title = "It", 
   Read... // what do I do here?
}

我主要担心的是:

C# 语言中是否有一个简单的 feature/pattern 可以实现此目的?

让 class 的不同实例实现不同的功能是不可能的。相反,您继承了一个新的 class,您可以在其中实现单独的行为。

public abstract class Book
{
   public string Title {get; set;}
   public abstract string Read(int pageNum);
}

public class ITBook : Book
{
   public override string Read(int pageNum)
   {
      // Code here
   }
}

然后像这样使用 class:

public static Book It => new ITBook()
{ 
   Title = "It", 
}

您可以使用本书 class 中委托类型的 属性 在本书 class 的不同实例中使用不同的函数,但这些函数无法访问它们将被使用的实例的其他属性和方法。

NineBerry说的很有道理。

还有另一种方法可以完成您可能想要的。如果你想动态地将 read 方法实现注入到 Book 中。这可以看作是strategy pattern。并且可以像在许多语言中一样作为接口来完成,但在 C# 中以最简单的形式它可以由委托来完成。示例:

public class Book{
   Func<int, string> readFunc;
   public Book(Func<int, string> readFunc)
   {
     this.readFunc = readFunc;
   }
   public string Title {get; set;}
   public string Read(int pageNum) { return readFunc(pageNum); }
}

然后用作:

public static Book It => new Book(){
   Title = "It", 
   Read = (pageNum) => ... // Do actual reading in delegate
}

编辑:关于要求的更多细节(但仍然不是所有事情都是显而易见的)我会做这样的事情:

public class Tenant 
{
  // core things go here
  public Extensions Extensions { get; }
}

public class Extensions : IEnumerable<IExtension>
{
  private IList<IExtension> list = new List<IExtension();
  private Tenant { get; set; }

  public Extensions(Tenant tenant)
  {
    Tenant = tenant;
  }

  public void Add(IExtension extension)
  {
    extension.Tenant = Tenant;
    list.Add(extension);
  }
}

public interface IExtension
{
  Tenant { get; set; }
  // shared interface of extensions if any can be abstracted
}

public interface ICoverPhotoExtension : IExtension
{
  Photo GetCoverPhoto();
}

public class FileCoverPhotoExtension : ICoverPhotoExtension 
{
  public Tenant { get; set; }
  Photo GetCoverPhoto() { } // gets photo from file
}

public class BlogCoverPhotoExtension : ICoverPhotoExtension 
{
  public Tenant { get; set; }
  Photo GetCoverPhoto() { } // gets photo from blog
}

用法:

Tenant tenant; // initialized somehow
var coverPhotoExtension = tenant.Extensions.FirstOrDefault<ICoverPhotoExtension>();
Photo photo = coverPhotoExtension?.GetCoverPhoto();
public Interface IBook{ 
   string Title {get; set;}
   func<int,string> ReadPage
}

使用包含而不是继承。在上面的接口示例中,每本实现 IBook 的书中都有一个函数,它将 return 该页面的字符串。

public class MyBook : IBook{

   public Title : {get;set;} = "MyBook";
   public func<int,string> ReadPage =(pagenumber)=>{
       return GetText(pagenumber);
   }  
   public string GetText(int pageNumber){
      //read the page text by number here.
   }
}

我会将 GetText 做成一个类似于此的扩展方法,因此每本书都不需要自己实现 GetText。

public static class XBook{
    public static string GetText(this IBook book, int pageNumber){
        ///do the work here and returng string
    } 
}

要使用扩展方法概念:

using XBook;
public class MyBook : IBook{

   public Title : {get;set;} = "MyBook";
   public func<int,string> ReadPage =(pagenumber)=>{
       return this.GetText(pagenumber);
   }  
}

还有更多方法可以做到这一点...现在,试试吧。