是否可以创建具有动态签名的抽象方法?
Posted
技术标签:
【中文标题】是否可以创建具有动态签名的抽象方法?【英文标题】:Is it possible to create an abstract method with a dynamic signature? 【发布时间】:2021-10-27 22:47:41 【问题描述】:我有一个 .Net 5 Web Api 项目,其中多个控制器的行为类似于操作,应该始终返回状态码 200,Guid
代表因果关系 id。
我为这些命令处理程序创建了一个基类
[ApiController]
public abstract class CommandController : ControllerBase
[NonAction]
protected CausationIdResult CausationId(Guid causationId) => new(causationId);
public abstract Task<CausationIdResult> Handle(CancellationToken cancellationToken);
public sealed class CausationIdResult : OkObjectResult
public CausationIdResult(Guid causationId) : base(causationId)
一个示例实现可以是
public sealed class DoSomethingController : CommandController
[HttpPost("do-something")]
public override Task<CausationIdResult> Handle(CancellationToken cancellationToken)
// run logic here
// generate a unique queue id
// pass the queue id back to the client
return Task.FromResult(CausationId(Guid.NewGuid()));
但是如果我希望从该控制器操作中获得其他参数怎么办?例如。读取参数、查询还是正文?
这是另一个展示可能实现的示例
[HttpPost("do-something/id")]
public override Task<CausationIdResult> Handle(CancellationToken cancellationToken, [FromRoute] string id)
return Task.FromResult(CausationId(Guid.NewGuid()));
但显然这会导致编译错误,因为
没有合适的覆盖方法
是否可以像这样使用动态参数创建抽象方法?
public abstract Task<CausationIdResult> Handle(CancellationToken cancellationToken /* , a type that makes it possible to add all the additional parameters here */);
【问题讨论】:
【参考方案1】:最适合的可能是params
语法,但最后你不会弄清楚后续参数的含义。
为什么不采取完全不同的方法呢?就像使用 IDictionary
来存储 dynamic 参数一样。 动态,我的意思是CausationIdResult
,它是孤立的,不知道注入其中的可能值。
为了使其工作,您可以使用动态(因此是键值对)数据类型创建CausationResult
的实例。
哦,C# 也支持dynamic types。
最后我相信你有一个 X->Y 问题。当您的问题是跟踪结果类的输入时,您正在尝试解决编译问题。
【讨论】:
【参考方案2】:我会尝试解释您的问题并稍微调整解决方案。 原来的问题是:
应该始终返回带有 Guid 的状态代码 200 的操作
您正在尝试使用继承来解决这个问题,而这正是您遇到另一个问题的地方:
是否可以像这样使用动态参数创建抽象方法?
由于代码在 ASP.NET 核心堆栈中运行,我们现在可以使用更多工具来帮助我们解决最初的问题。如果您没有严格限制使用继承,则可以使用ASP.NET middleware 或ASP.NET MVC filters。 如examples 之一所述:
可以从控制器外部修改响应的内容。
你的过滤器看起来像这样:
public class HttpResponseCausationFilter : IActionFilter, IOrderedFilter
protected CausationIdResult CausationId(Guid causationId) => new(causationId);
public int Order get; = int.MaxValue - 10;
public void OnActionExecuting(ActionExecutingContext context)
public void OnActionExecuted(ActionExecutedContext context)
context.Result = new ObjectResult(CausationId(Guid.NewGuid()))
StatusCode = 200,
;
别忘了注册过滤器
services.AddControllers(options =>
options.Filters.Add(new HttpResponseCausationFilter()));
【讨论】:
以上是关于是否可以创建具有动态签名的抽象方法?的主要内容,如果未能解决你的问题,请参考以下文章
为啥继承具有名称签名的接口成员的 C# 抽象类至少需要实现其中一个?