如何定义必须由 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?
}
我主要担心的是:
- 让事情尽可能简单。在抽象 classes 下实现接口是可行的,但随着我添加更多实例,它让我需要担心 n*2 件事。
- 我将需要添加大量这些自定义函数 - 通过构造函数传递 Funcs 似乎很笨拙。
- 在实践中 - 这用于定义
Tenant
。 Tenants
是在内存中定义的,并且有许多静态属性,如 domain
、name
、adminEmail
等。这些是特定于租户的属性......但现在我我正在尝试实施特定于租户的 行为 - 例如 GetBooks
或 FilterUsers
。我想让实现尽可能简单。现在我的代码中到处都是 "If TenantA, do this, else if tenantB, do this..."。我正在尝试将所有特定于租户的逻辑和细节整合到一个地方 - 在 Tenant
class. 的实例上
- 租户特定行为的更多示例 - 您有一个 SaaS 论坛软件。在论坛 A 的主页上,您
GetCoverPhoto
通过读取静态文件。在论坛 B 的主页上,您 GetCoverPhoto
通过阅读博客主页。目前,我说 "If Forum A, do this, else If Forum B, do this"。这是我想在租户对象上而不是在代码中定义的特定于租户的行为类型。我不想在我的核心逻辑中包含任何特定于租户的代码。
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);
}
}
还有更多方法可以做到这一点...现在,试试吧。
假设我有 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?
}
我主要担心的是:
- 让事情尽可能简单。在抽象 classes 下实现接口是可行的,但随着我添加更多实例,它让我需要担心 n*2 件事。
- 我将需要添加大量这些自定义函数 - 通过构造函数传递 Funcs 似乎很笨拙。
- 在实践中 - 这用于定义
Tenant
。Tenants
是在内存中定义的,并且有许多静态属性,如domain
、name
、adminEmail
等。这些是特定于租户的属性......但现在我我正在尝试实施特定于租户的 行为 - 例如GetBooks
或FilterUsers
。我想让实现尽可能简单。现在我的代码中到处都是 "If TenantA, do this, else if tenantB, do this..."。我正在尝试将所有特定于租户的逻辑和细节整合到一个地方 - 在Tenant
class. 的实例上
- 租户特定行为的更多示例 - 您有一个 SaaS 论坛软件。在论坛 A 的主页上,您
GetCoverPhoto
通过读取静态文件。在论坛 B 的主页上,您GetCoverPhoto
通过阅读博客主页。目前,我说 "If Forum A, do this, else If Forum B, do this"。这是我想在租户对象上而不是在代码中定义的特定于租户的行为类型。我不想在我的核心逻辑中包含任何特定于租户的代码。
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);
}
}
还有更多方法可以做到这一点...现在,试试吧。