用三元运算符理解C#编译错误

时间:2013-01-03 17:34:28

标签: c# inheritance if-statement ternary-operator

我已经从Wrox Professional ASP.NET 4.0 MVC 4书籍,第179页(“了解Web应用程序中的安全性向量”一章)中复制了以下代码,并对其进行了少量修改protected并将其作为实用程序方法存储在我的抽象应用程序范围Controller

protected ActionResult RedirectToLocal(string returnUrl)
{
    if (Url.IsLocalUrl(returnUrl))
    {
        return Redirect(returnUrl);
    }
    else
    {
        return RedirectToAction("Index", "Home");
    }
}

上面的代码旨在保护MVC应用程序免受开放式重定向攻击,这些攻击不是问题的主题。

代码显然格式正确,编译并且我相信它有效。

当“巧妙地”将上面的代码更改为以下单行

时,就会出现问题
return (Url.IsLocalUrl(returnUrl)) ? Redirect(returnUrl) : RedirectToAction("Index", "Home");

上面的单行应该与扩展代码完全相同(不,ReSharper不建议我替换,这是我的主动)。

编译错误如下:there is no implicit conversion between System.Web.Mvc.RedirectResult and System.Web.Mvc.RedirectToRouteResult

然后ReSharper来帮助并建议以下修改

return (Url.IsLocalUrl(returnUrl)) ? (ActionResult) Redirect(returnUrl) : RedirectToAction("Index", "Home");

问题是“为什么我必须投射重定向方法”?

由于RedirectRedirectToAction都返回ActionResult的子类(通过F12验证),并且该子类是函数的返回值,因此它应该是自动兼容的。或者至少,根据我对C#的了解,要么两个代码都编译,要么两者都不编译。

更一般地说,问题可以重新拟定如下:

假设我有A,B和C类

abstract class A {}
class B: A{}
class C: A{}

假设以下功能有效

private A Function(){
    if (condition) return new B();
    else return new C();
}

为什么下面的单行程序无法编译?

private A Function(){
    return (condition) ? new B(): new C();
}

2 个答案:

答案 0 :(得分:6)

它不会编译,因为编译器根据两个返回值之一决定一个内容的返回类型。由于类型B不是派生类型C,反之亦然,这两种类型不是互斥的,而if(作为一个整体)的返回类型不能以这种方式派生。

如果您希望在单行中执行此操作,则必须将返回值强制转换为要返回的类型,即类型A.

private A Function(){
    return (condition) ? ((A)new B()): ((A)new C());
}

更新:我没有看到你已经在你的问题中进行了投射,我很抱歉。

答案 1 :(得分:2)

编译器期望在条件语句中使用相同的返回类型,因此它希望这两者都是相同的类型。如果将选项转换为ActionResult,它将起作用。您可以通过仅投射最后一个来与编译器相处。

return (Url.IsLocalUrl(returnUrl)) ? (ActionResult)Redirect(returnUrl) : (ActionResult)RedirectToAction("Index", "Home");