Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
394 views
in Technique[技术] by (71.8m points)

inheritance - Understanding C# compilation error with ternary operator

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();
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.

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

UPDATE: I didn't see that you already do the casting in your question, my apologies.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...