I have copied the following code from Wrox Professional ASP.NET 4.0 MVC 4
book, page 179 (Chapter "Understanding the Security Vectors in a Web Application") with the little modification of making it protected
and storing as utility method in my abstract application-wide Controller
protected ActionResult RedirectToLocal(string returnUrl)
{
if (Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
The code above is aimed at securing the MVC application from open redirection attacks, which are not subject of the question.
The code is obviously well-formed, compiles and I trust it works.
The problem arises when "smartly" changing the code above into the following one-liner
return (Url.IsLocalUrl(returnUrl)) ? Redirect(returnUrl) : RedirectToAction("Index", "Home");
The one-liner above is supposed to do exactly the same as the extended code (no, ReSharper didn't suggest me to replace, it was my initiative).
The compilation error is the following: there is no implicit conversion between System.Web.Mvc.RedirectResult and System.Web.Mvc.RedirectToRouteResult
.
ReSharper then comes to help and suggests the following modification
return (Url.IsLocalUrl(returnUrl)) ? (ActionResult) Redirect(returnUrl) : RedirectToAction("Index", "Home");
The question is "why do I have to cast Redirect method"?
Since both Redirect
and RedirectToAction
return a subclass of ActionResult
(verified via F12) and that subclass is the return value of the function, it should be automatically compatible. Or at least, in my knowledge of C#, either both codes compile or they both don't.
To be more general, the question could be reformulated as follows:
Suppose I have class A, B and C
abstract class A {}
class B: A{}
class C: A{}
And suppose the following function works
private A Function(){
if (condition) return new B();
else return new C();
}
Why the following one-liner doesn't compile?
private A Function(){
return (condition) ? new B(): new C();
}
The compiler expects the same return type in a conditional statement, so it expects both of these to be the same type. If you cast the options to ActionResult, it will work. You may be able to get along with the compiler by only casting the last one.
It doesn't compile because the compiler decides what the return-type of the one-liner is based upon one of the two return-values. Since type B doesn't derive of type C, or the other way around, the two types are not mutually exclusive, and the return type of the if (as a whole) cannot be derived that way.
If you would want to do it in a one-liner, you have to cast the return-values to the type that you want to return, which is type A.
UPDATE: I didn't see that you already do the casting in your question, my apologies.