C# 如何定义必须由类实例实现的函数的签名?
假设我有一本教科书: 我希望每本书都有一个Read函数,它返回一个字符串并接受一个页码——但我知道,每本书的内部结构都会有所不同。如何定义必须由此类实例实现的函数的签名 大概是这样的:C# 如何定义必须由类实例实现的函数的签名?,c#,c#-6.0,C#,C# 6.0,假设我有一本教科书: 我希望每本书都有一个Read函数,它返回一个字符串并接受一个页码——但我知道,每本书的内部结构都会有所不同。如何定义必须由此类实例实现的函数的签名 大概是这样的: public class Book{ // need to make this abstract? public string Title {get; set;} public abstract string Read(int pageNum); } // I want to define inst
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?
}
我主要关注的是:
让事情尽可能简单。在抽象类下实现接口是可行的,但当我添加更多实例时,它给我带来了n*2件需要担心的事情。
我将需要添加大量这些自定义函数-通过构造函数传递func似乎很难。 在实践中-这用于定义租户。租户在内存中定义,并具有许多静态属性,如域、名称、adminEmail等。这些是特定于租户的属性。。。但现在我正试图实现特定于租户的行为,比如GetBooks或FilterUsers。我希望实现尽可能简单。现在我要如果TenantA,做这个,否则如果tenantB,做这个。。。散布在我的代码中。我试图将所有特定于租户的逻辑和细节整合到一个地方,即租户类的实例上。 租户特定行为的进一步示例-您有一个SaaS论坛软件。在论坛A的主页上,你可以通过读取静态文件获得封面照片。在论坛B的主页上,你可以通过阅读博客主页获得封面照片。现在,我说如果论坛A,做这个,否则如果论坛B,做这个。这是我想在租户对象上定义的租户特定行为类型,而不是在代码中定义。我的核心逻辑中不需要任何特定于租户的代码。
C语言中是否有一个简单的特性/模式可以实现这一点?一个类的不同实例以不同的方式实现函数是不可能的。相反,您将继承一个新类,在该类中实现单独的行为
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
}
}
然后像这样使用类:
public static Book It => new ITBook()
{
Title = "It",
}
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
}
您可以在Book类中使用委托类型的属性在Book类的不同实例中使用不同的函数,但这些函数将无法访问它们将使用的实例的其他属性和方法。不可能让类的不同实例以不同方式实现函数。相反,您将继承一个新类,在该类中实现单独的行为
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
}
}
然后像这样使用类:
public static Book It => new ITBook()
{
Title = "It",
}
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
}
您可以在Book类中使用委托类型的属性在Book类的不同实例中使用不同的函数,但这些函数将无法访问实例的其他属性和方法。NineBerry所说的非常有效 还有一种方法可以实现你可能想要的。如果您想动态地将read方法实现注入到一本书中。这可以看作是一个错误。可以像在许多语言中一样作为接口完成,但在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 ITBook()
{
Title = "It",
}
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();
NineBerry所说的非常正确 还有一种方法可以实现你可能想要的。如果您想动态地将read方法实现注入到一本书中。这可以看作是一个错误。可以像在许多语言中一样作为接口完成,但在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 ITBook()
{
Title = "It",
}
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();
要使用扩展方法概念,请执行以下操作:
using XBook;
public class MyBook : IBook{
public Title : {get;set;} = "MyBook";
public func<int,string> ReadPage =(pagenumber)=>{
return this.GetText(pagenumber);
}
}
有更多的方法可以做到这一点。。。现在,试试看
要使用扩展方法概念,请执行以下操作:
using XBook;
public class MyBook : IBook{
public Title : {get;set;} = "MyBook";
public func<int,string> ReadPage =(pagenumber)=>{
return this.GetText(pagenumber);
}
}
有更多的方法可以做到这一点。。。现在,试一试。@AlexD我已经试过了-我会用我的问题来更新我的问题。啊,好吧,那么,抽象不适用于这里。你可以考虑阅读一个委托。通过构造函数传递函数看起来真的很笨拙。Read=pageNumber=>LoadPageNumber是否笨重?它正好说明了您需要说的:对于Book的这个实例,您可以通过调用LoadPage方法来加载页面。为每个图书实例指定不同的阅读行为的方法是为每个图书实例指定不同的阅读行为。@JoeWhite-无需讽刺。根据我的观察,一个包含20项的构造函数是不可取的。更不用说类声明中每个函数n*2行,每个func一行,然后每个用法一行。即使答案的作者也同意。仍然不确定我的要求是否正确,但在我的编辑中有一些详细的答案。@AlexD我已经尝试过了-我将更新我的问题,说明我在哪里挣扎。啊,好吧,那么,抽象不适用于这里。你可以考虑阅读一个委托。通过构造函数传递函数看起来真的很笨拙。Read=页码
=>LoadPageNumber是否笨拙?它正好说明了您需要说的:对于Book的这个实例,您可以通过调用LoadPage方法来加载页面。为每个图书实例指定不同的阅读行为的方法是为每个图书实例指定不同的阅读行为。@JoeWhite-无需讽刺。根据我的观察,一个包含20项的构造函数是不可取的。更不用说类声明中每个函数n*2行,每个func一行,然后每个用法一行。即使答案作者也同意。我仍然不确定reqs是否正确,但在我的编辑中有一些详细的答案。您可以在Book类中使用委托类型的属性在Book类的不同实例中使用不同的函数,但是这些函数将无法访问它们将使用的实例的其他属性和方法。事实并非如此。如果委托是一个闭包,但它需要在构建Book对象之后进行构造。我正试图使代码占用空间尽可能小。。。如果我有10本不同的书,那就是10个不同的接口和静态类=n*2件需要担心的事情。有没有一种简单的方法可以让我用n件事来实现这一点?如果你需要在代码中为每本书实现不同的页面检索,那么你的设计中还有一些非常错误的地方。如果您能告诉我们更多关于问题的实际背景,会更容易提供帮助。@NineBerry我已经用更多的上下文更新了我的问题-谢谢。您可以在Book类中使用委托类型的属性在Book类的不同实例中使用不同的函数,但是这些函数将无法访问它们将使用的实例的其他属性和方法。事实并非如此。如果委托是一个闭包,但它需要在构建Book对象之后进行构造。我正试图使代码占用空间尽可能小。。。如果我有10本不同的书,那就是10个不同的接口和静态类=n*2件需要担心的事情。有没有一种简单的方法可以让我用n件事来实现这一点?如果你需要在代码中为每本书实现不同的页面检索,那么你的设计中还有一些非常错误的地方。如果你告诉我们更多关于这个问题的实际背景,帮助会更容易。@NineBerry我已经用更多的上下文更新了我的问题-谢谢。我用我的顾虑评论了NineBerry的答案-这可能更好,但你能证明它的用法吗?为你更新的帖子我用我的顾虑评论了NineBerry的答案-这可能更好,但你能证明它的用法吗?更新的帖子对于你,感谢这个-虽然它看起来有点脏-如果我有20个不同的函数需要声明呢?这绝对不是预期用途。这真的很酷,很可能是我要去的方向-谢谢!有什么方法可以让我发电子邮件给你,要求你提供更多细节的有偿帮助吗?你的评论让我想到了这个秘密。只需在第一个链接上搜索我和联系人。谢谢这一点-虽然它看起来有点脏-如果我有20个不同的功能需要声明怎么办?这绝对不是预期用途。这真的很酷,很可能是我要去的方向-谢谢!有什么方法可以让我发电子邮件给你,要求你提供更多细节的有偿帮助吗?你的评论让我想到了这个秘密。只需谷歌我和联系上的第一个链接。