Как ASP.NET Core может преобразовать любой тип в ActionResult <T>возвращаемый тип действий контроллера? - PullRequest
3 голосов
/ 02 апреля 2019

У меня есть простое действие в контроллере WebApi в ASP.NET Core 2.2, которое выглядит следующим образом:

[HttpGet("test123")]
public ActionResult<string> Test123()
{
    return new OkResult();
}

Это прекрасно компилируется, но мне интересно, как это возможно, что OkResult объект конвертируется в ActionResult<string>?

Эти классы имеют различную цепочку наследования: OkResult -> StatusCodeResult -> ActionResult в то время как ActionResult<TValue> только реализует IConvertToActionResult Другими словами, ActionResult<string> не является базовым типом для OkResult класса.

Если я сделаю это вручную и поменяю код на:

[HttpGet("test123")]
public ActionResult<string> Test123()
{
    var a = new OkResult();
    var b = a as ActionResult<string>;  // Error CS0039

    return b;
}

код не скомпилируется с ошибкой преобразования:

Ошибка CS0039: Невозможно преобразовать тип «Microsoft.AspNetCore.Mvc.OkResult» в «Microsoft.AspNetCore.Mvc.ActionResult» с помощью преобразования ссылок, преобразования в бокс, распаковки, преобразования в оболочку или преобразования нулевого типа

Как возможно, что первый код работает, а второй нет? Как тип возвращаемого значения конвертируется из объектов, которые не имеют общего базового типа?

Ответы [ 2 ]

2 голосов
/ 02 апреля 2019

В первом примере используется неявный пользовательский оператор преобразования типов, который выглядит как this :

public static implicit operator ActionResult<TValue>(ActionResult result)
{
    return new ActionResult<TValue>(result);
}

Ваш второй пример, использующий as, не может использовать оператор неявного преобразования, как, в соответствии с документами , это:

... выполняет только эталонные преобразования, преобразования с нулевым значением и преобразования в боксы. Оператор as не может выполнять другие преобразования, такие как пользовательские преобразования, которые вместо этого должны выполняться с использованием приведенных выражений.

2 голосов
/ 02 апреля 2019

Следующие два неявных оператора из ActionResult<TValue>

/// <summary>
/// Implictly converts the specified <paramref name="value"/> to an <see cref="ActionResult{TValue}"/>.
/// </summary>
/// <param name="value">The value to convert.</param>
public static implicit operator ActionResult<TValue>(TValue value)
{
    return new ActionResult<TValue>(value);
}

/// <summary>
/// Implictly converts the specified <paramref name="result"/> to an <see cref="ActionResult{TValue}"/>.
/// </summary>
/// <param name="result">The <see cref="ActionResult"/>.</param>
public static implicit operator ActionResult<TValue>(ActionResult result)
{
    return new ActionResult<TValue>(result);
}

Источник

Это то, что позволяет использовать несколько типов возврата в действии.

[HttpGet("test123")]
public ActionResult<string> Test123() {
    if(someCondition) return "String value"; //<--String
    return Ok(); //<-- OkResult
}

Когда возвращается строка, вызывается оператор ActionResult<TValue>(TValue value), возвращающий действительный ActionResult<TValue> и наоборот другого оператора.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...