为什么ASP.NET MVC ActionResult是一个抽象类?

5
ASP.NET MVC 中,ActionResult 类是所有控制器中 action 方法返回的结果的基类,它被定义为一个抽象类,只有一个方法 (© Microsoft):
public abstract void ExecuteResult(ControllerContext context);

你能想到这种设计的具体原因吗?特别是,对我来说,似乎有点奇怪,

  • 没有 IActionResult 接口,
  • 如果有这样的接口,那么根本不需要该类。

毕竟,如果这是一个接口而不是抽象类,那么创建新的 ActionResult 就不需要扩展基类 - 只需正确实现 IActionResult 即可。在一个没有多重继承的世界(或语言)中,这个优势对我来说似乎非常重要。


我给微软ASP.NET MVC项目经理Phil Haack发送了这个问题的链接,希望他能在接下来的几天里抽出时间解释一下。 - Eric Schoonover
在这种特定情况下,您是否遇到了特定的阻塞场景? - Haacked
不,其实不是。我只是在一般地思考各种MVC框架,因为我在工作中使用ASP.NET MVC进行项目开发,所以我也看了看它的一些特性是如何实现的。在做这件事时,我注意到了这个看似奇怪的抽象类。 :) - hangy
5
ASP.NET MVC的ActionResult类为什么是抽象类?ActionResult类是ASP.NET MVC中用于表示控制器操作方法(Action Method)的返回类型的基类。 它被设计为一个抽象类,因为它本身不提供任何实际的实现,而是留给具体的返回类型来实现。 这种设计使得 ASP.NET MVC 更加灵活和可扩展,开发人员可以根据自己的需要创建自定义的ActionResult子类,并在其中实现自己的逻辑。 - dugas
5个回答

13

接口很适合让一个类实现多个契约,特别是当您知道某种类型必须是两种不同的事物时。但在某些情况下,这可能会鼓励创建具有过多职责的类型。

操作结果具有单一职责,似乎没有任何情况需要将一个对象同时作为操作结果和其他东西。即使需要,也可以通过组合来实现。因此,在这种情况下,我们选择 ABS 以便在 RTM 后允许更大的灵活性进行必要的更改。

然而,如果有特定的情况需要使用接口,则可以考虑使用。我们随时可以以不破坏性的方式进行后续操作。

您甚至可以通过编写自己的操作调用程序来自行完成,这只需要您实现 IActionInvoker(一个接口),并且该调用程序可以检查您自己的 IActionResult 而不是 ActionResult。


今天我遇到了一个问题,这让我陷入了困境。我想将ActionResult实现为ExpandoObject,以便控制器可以动态地向ActionResult添加成员。但是我的类不能同时是ActionResult和ExpandoObject,除非使用多重继承... - joshperry
你可以创建一个ActionResult类,同时实现IDynamicMetaObjectProvider接口(参见http://msdn.microsoft.com/en-us/library/system.dynamic.idynamicmetaobjectprovider.aspx)。在该接口的实现中,你可以委托给一个内部的Expando对象。 - Haacked
1
喜欢Phil Haack来自ASP.NET MVC团队并给出明确的答案。他们在社区中的参与值得赞扬。 - Keith Adler

2

我猜测这是因为他们预计ActionResult在CTP / beta的生命周期内会获得方法和属性。如果它是一个接口,每次对IActionResult的更改都会破坏现有代码。而向抽象基类添加另一个方法不会引起任何问题。


在CTP阶段已经进行了重大变更,所以这可能不是一个合适的理由。 :) 无论如何,你的猜测可能接近他们的想法。我希望他们能在发布前决定一些接口而不是抽象类。 - hangy

1

你实现接口并从抽象类继承。
对我来说,这是“属于类型”或“像类型行事”的区别。

由于C#不支持多重继承,您被迫将类定义为ActionResult,而不是像ActionResult一样的东西。

将其与EventArgs类进行比较。为什么继承EventArgs而不是IEventArgs接口有意义。好吧,因为EventHandler携带的是EventArgs类型的内容,而不是像EventArgs类一样的东西。


1

我知道这不完全是你要找的,但为了好玩,我打开了MVC3源代码,将ActionResult更改为IActionResult,运行了一些查找和替换操作,一切都构建得很好。

对我来说,这意味着ActionResult是一个API原因的抽象类。也许这就像MVC团队希望你能够使用字段一样简单,或者他们不想让人们有能力做疯狂的IActionResult、ISomething、IMyNuttyThing之类的事情。


1
我认为IActionResult有帮助的一个场景是依赖注入。我想要一个控制器集合,可以在SPA和Razor UI之间共享。在配置中,我想要动态设置应用程序类型,并且让我的控制器能够正常工作。
public ActionResult Get(){
  var customer = new Customer();
  return View(customer);
}

我希望根据应用程序类型在运行时确定具体的视图方法,例如Json()或ViewResult()。
对于这两种情况,我传递给结果的对象将是相同的。
这样说您是否明白?或者说,这是否可以在没有IActionResult的情况下实现?

1
欢迎来到Stack Overflow。您在一个专门用于回答的部分发布了您的问题。请阅读FAQ,其中包含许多有用的信息,包括提问指南 - Perception

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接