c# - 如何定义必须由类的实例实现的函数的签名?

标签 c# c#-6.0

假设我有一个类 Book:

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

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

是这样的:

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?
}

我主要担心的是:

  • 让事情尽可能简单。在抽象类下实现接口(interface)是可行的,但随着我添加更多实例,它让我需要担心 n*2 件事。
  • 我将需要添加大量这些自定义函数 - 通过构造函数传递 Funcs 似乎很笨拙。
  • 在实践中 - 这用于定义 TenantTenant 是在内存中定义的,并且具有许多静态属性,例如 domainnameadminEmail 等。这些是特定于租户的属性...但现在我正在尝试实现特定于租户的行为 - 例如GetBooksFilterUsers。我想让实现尽可能简单。现在,我的代码中到处都是“如果是租户 A,则执行此操作,否则,如果是租户 B,则执行此操作……”。我正在尝试将所有特定于租户的逻辑和细节整合到一个地方 - 在 Tenant 类的实例上。
  • 租户特定行为的更多示例 - 您有一个 SaaS 论坛软件。在论坛 A 的主页上,您可以通过读取静态文件来GetCoverPhoto。在论坛 B 的主页上,您通过阅读博客主页来GetCoverPhoto。目前,我说“如果是论坛 A,则执行此操作,否则如果是论坛 B,则执行此操作”。这是我想在租户对象上而不是在代码中定义的特定于租户的行为类型。我不想在我的核心逻辑中包含任何特定于租户的代码。

C# 语言中是否有一个简单的功能/模式可以实现这一点?

最佳答案

NineBerry 说的很有道理。

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

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();

关于c# - 如何定义必须由类的实例实现的函数的签名?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41785425/

相关文章:

c# - Dropzone.js 已附加

c# - UTF8Encoding.UTF8.GetBytes 和 Encoding.UTF8.GetBytes 之间有什么区别吗?

c# - 在 C# 中测试/注入(inject)私有(private)字段的最佳做法是什么

c# - WPF 使用索引变量将 TextBox 绑定(bind)到 List<string>

c# - 具有多个 OR 条件的 EF core 连接

c# - TfvcTemplate.12.xaml 构建配置在哪里

c# - .NET 4.6 和 C#6 中是否集成了动态语言运行时 (DLR)?

c# - 属性 - 按值还是引用?

c# - 使用默认值检查 C# 6 中的 null

C#6 : nameof() current property in getter/setter