带有可选参数的 MVC 操作——哪个更好?

Posted

技术标签:

【中文标题】带有可选参数的 MVC 操作——哪个更好?【英文标题】:MVC Action with Optional Parameters -- which is better? 【发布时间】:2012-04-11 23:13:02 【问题描述】:

在您的动作签名中使用以下两种替代方案是否有任何优点/缺点:

public ActionResult Action(int? x) // get MVC to bind null when no parameter is provided

    if(x.HasValue)
    
        // do something
    

public ActionResult Action(int? x = null) // C# optional parameter (virtual overload)

    if(x.HasValue)
    
        // do something
    

【问题讨论】:

我认为在第一种情况下你需要参数,而在另一种情况下,如果没有传递参数,它会假定 null,所以它实际上是你真正想要的第二个(只是猜测)。 @V4Vendetta no 第一种情况在作为 Web 请求调用时不需要显式参数。 【参考方案1】:

我在实践中从未见过第二个动作签名,也看不出它有什么用处。

第一个通常涵盖所有场景:

如果不发送任何参数 (GET /somecontroller/action),x 参数的值将在操作内为空 如果发送了 x 参数,但它不是有效的整数 (GET /somecontroller/action?x=abc),则 x 参数的值将在操作中为 null,并且模型状态将无效 如果发送了 x 参数并且值表示有效整数 (GET /somecontroller/action?x=123),则将为其分配 x。

在我的示例中,我使用了带有查询字符串参数的 GET 请求,但显然这同样适用于其他 HTTP 动词,如果 x 是一个路由参数。

【讨论】:

很好的答案,但请注意 int? x = null 什么都不做。 null 是默认值 嗨@Darin,我收到了一个没有发送参数的请求,但我的参数值没有设置为null,而是对象的默认值。我更喜欢空值。关于可能导致它的任何想法?我会提出一个新问题,但它可能会被当作骗子关闭! @DoctaJonez 假设您在签名中指定了一个可以为空的类型,例如 int? @ZaidMasud 是的,它是一个可为空的 int。我发现它正在从其他地方获取价值。我不记得确切的细节,但它正在获取碰巧具有相同名称的不同字段(不在模型中)的默认值。抱歉,我不能更具体!【参考方案2】:

如果它是null以外的任何其他值,您只需要指定可选参数值。

如果在重载或对 Action 的调用中未指定任何内容,MVC3 将自动将 null 设置为您的参数值。

但值得注意的是,如果签名中此参数后有任何非可选参数,则必须在调用中指定null

因此最好将所有可选参数放在签名的末尾。

【讨论】:

请扩展您所说的“仍然为空”是什么意思?确实,当没有提供参数时,MVC 框架会将其绑定到空值,但请注意,它是 MVC 为您执行此操作的。在第二种选择中,我们明确指定了重载。【参考方案3】:

最佳 Asp.net MVC 解决方案 - 使用操作方法选择器

为什么不通过删除不必要的代码分支来简化控制器操作方法,并拥有如下所示的这种代码:

public ActionResult Index()

    // do something when there's no id


[RequiresRouteValues("id")]
public ActionResult Index(int id)

    // do something when id is present

这当然是可能的,只要您提供RequiresRouteValuesAttribute 操作方法选择器的非常简单的代码即可。您可以在 this blog post 中找到执行此操作的代码。

在我看来,这是解决这个问题的最佳方法,因为:

    它通过删除不必要的分支来简化代码 使代码更易于维护(由于复杂性较低) 尽可能扩展 Asp.net MVC 框架 保持参数类型应有的状态,而不需要使它们可以为空 等

无论如何。有关此技术的所有细节都在链接的帖子中进行了详细说明。

【讨论】:

这只适用于路由定义中定义的id参数吗?如果该参数被称为其他名称,我相信 RequiresRouteValues 属性将不再需要,并且解决方案将类似于我的第二个代码示例,当然分支更少。感谢您的想法,但您可能会在这里回答不同的问题。 不,这适用于任何控制器操作参数。这并不意味着提供的参数名称必须在路由定义中。它们可能也与查询值、发布字段有关......不,它与您的第二个示例完全不同。这个属性是一个动作方法选择器而不是一个动作过滤器......如果特定动作参数不是请求的一部分(作为路由值、查询变量或发布字段的一部分),则根本不会执行此方法。 MVC 不会将此方法解析为请求处理的可能候选者。 @zooone9243:当然,我的回答并没有直接回答你提出的问题,但它提供了一个更好、更清晰的解决方案,不会让你回答你的问题首先。 罗伯特 我建议将其发布为this question的答案。 @ZaidMasud:这是一个早就应该回答的老问题,已经得到了充分的回答,涵盖了 90% 的此类案例。动作方法选择器是 MVC 中的高级主题。动作重命名不是...

以上是关于带有可选参数的 MVC 操作——哪个更好?的主要内容,如果未能解决你的问题,请参考以下文章

C#4.0中的方法重载与可选参数[重复]

ASP.NET MVC 5 中的路由可选参数

使用可选关键字参数定义类的 __init__ 方法的更好方法是啥?

MVC ActionLink 从当前 url 添加所有(可选)参数

ASP.Net MVC 2 RC2:当所有可选参数为空时,自定义路由返回 404

如何使用可选的查询字符串参数测试 MVC 路由