【问题标题】:Is it possible to create an abstract method with a dynamic signature?是否可以创建具有动态签名的抽象方法?
【发布时间】:2025-12-12 18:50:01
【问题描述】:

我有一个 .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 */);

【问题讨论】:

    标签: c# .net-core asp.net-core-webapi .net-5


    【解决方案1】:

    最适合的可能是params语法,但最后你不会弄清楚后续参数的含义。

    为什么不采取完全不同的方法呢?就像使用 IDictionary 来存储 dynamic 参数一样。 动态,我的意思是CausationIdResult,它是孤立的,不知道注入其中的可能值。

    为了使其工作,您可以使用动态(因此是键值对)数据类型创建CausationResult 的实例。

    哦,C# 也支持dynamic types

    最后我相信你有一个 X->Y 问题。当您的问题是跟踪结果类的输入时,您正在尝试解决编译问题。

    【讨论】:

      【解决方案2】:

      我会尝试解释您的问题并稍微调整解决方案。 原来的问题是:

      应该始终返回带有 Guid 的状态代码 200 的操作

      您正在尝试使用继承来解决这个问题,而这正是您遇到另一个问题的地方:

      是否可以像这样使用动态参数创建抽象方法?

      由于代码在 ASP.NET 核心堆栈中运行,我们现在可以使用更多工具来帮助我们解决最初的问题。如果您没有严格限制使用继承,则可以使用ASP.NET middlewareASP.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()));
      

      【讨论】:

        最近更新 更多