Reputation: 17
In the below example, GET
method has return type of
ActionResult<SomeAltResult>
but the return statement returns OKResult
with an IEnumerable
of WeatherForecast
and still it is compiling successfully.
I am trying to understand, if I can return anything, what is the point of having generic ActionResult<T>
? I can use ActionResult
or IActionResult
.
If ActionResult<T>
does not inherit any class or interface chain of OkObjectResult
then how is polymorphism working here?
namespace WebApplication1.Controllers
{
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm","Balmy", "Hot", "Sweltering", "Scorching"
};
[HttpGet(Name = "GetWeatherForecast")]
public ActionResult<SomeAltResult> Get()
{
var x = Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
return Ok(x);
}
}
public class SomeAltResult
{
public string Name { get; set; }
}
Upvotes: 1
Views: 143
Reputation: 233347
If
ActionResult<T>
does not inherit any class or interface chain ofOkObjectResult
then how is polymorphism working here?
The ActionResult<T>
class defines an implicit conversion from any ActionResult
to ActionResult<T>
, which explains why it compiles.
Code like this also compiles:
ActionResult<SomeAltResult> actionResult = Ok(x);
That conversion most likely makes use of the constructor overload that takes any ActionResult
as input. Notice that it's not constrained on the generic type parameter in any way. Thus, you can use any ActionResult
, including OkObjectResult
.
I am trying to understand, if I can return anything, what is the point of having generic
ActionResult<T>
? I can useActionResult
orIActionResult
.
It is, indeed, an odd API design. Consider this variation of the OP code:
ActionResult<SomeAltResult> actionResult = Ok(x);
SomeAltResult? value = actionResult.Value; // null
return Ok(value);
This also compiles, but the web resource now returns an empty result. This happens because actionResult.Value
returns null
since it has no value of the type T
.
I can't explain that API design choice. Such silent failures indicate to me an API design flaw. Code like that shouldn't be allowed to compile without warnings.
The reason that the OP works despite of all this is that the only thing that the ASP.NET framework cares about is whether a Controller Action returns an IActionResult, and the ExecuteResultAsync method doesn't care about generics. It only coverts the IActionResult
object to an HTTP response, and at the boundaries, static types don't exist.
Upvotes: 1