Как перегружать и возвращать несколько типов с помощью метода async C #?

Я хочу, чтобы куча GetDataAsync()методов была перегружена, чтобы возвращать различные наборы данных на основе требуемого типа. Если функция не была отключена, я мог бы перегружать по параметрам:public void GetData(int userId, out int age, out string name) { ... } public void GetData(int userId, out string name, out string address) { ... }

async

Но stringне допускается использование asyncметодов. Затем я попытался использовать generics для перегрузки (я изменил intи intдля других типов, поскольку этот трюк недействителен для закрытых классов):

public async Task<Tuple<TName, TAddress>> GetDataAsync<TName, TAddress>(int userId)
    where TAddress : Address where TName : Name
{ ... }
public async Task<Tuple<TAge, TName>> GetDataAsync<TAge, TName>(int userId)
    where TAge : Age where TName : Name
{ ... }

Но я считаю, что специализация шаблонов на самом деле не существует в C #, поэтому они считаются одной и той же функцией.

Уродливый хак, который позволяет эту перегрузку, передает в буферы, которые функция заполняет:

public async Task GetDataAsync(int userId, int[] id_output, string[] name_output)
{
    await Task.Delay(10);
    id_output[0] = 60;
    name_output[0] = "Freddy";
}

public async Task GetDataAsync(int userId, string[] name_output, string[] address_output)
{
    await Task.Delay(10);
    name_output[0] = "Freddy";
    address_output[0] = "Elm Street";
}

Но у этого хака есть плохой API. (Было бы немного безопаснее использовать список в качестве буфера.) Есть ли какой-либо правильный способ C # для получения разных типов данных из перегрузки async? Если я должен, я буду включать типы данных в имена функций вместо перегрузки, но это кажется излишне подробным. А поскольку функции абстрактной базы данных звонят, у некоторых из них действительно есть очень длинные имена! (Эти функции будут в основном иметь более одного вызывающего, следовательно, желание определять их централизованно, а не в классе, из которого они вызваны.)

c#,async-await,overloading,method-overloading,

0

Ответов: 2


1

out были созданы параметры для возврата нескольких значений, но они не работают с асинхронными методами, потому что реальный метод возвращается до завершения концептуального метода.

Вот почему кортежи были добавлены к языку.

Кортежи представляют собой слабо связанную совокупность значений. Они не предназначены для представления базы данных raw, сущности или всего, что имеет свой собственный смысл / концепцию.

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

То, что вы, похоже, ищете, - это дженерики :

Task<Response> GetAsync<Request, Response>(TRequest request);

0

Типичное и относительно чистое решение было вызвано ответом Пауло Моргадо. RequestКласс оборачивает прежние параметры, которые не могут быть использованы для перегрузки , потому что они всегда были такими же - идентификатор пользователя и маркер. Параметры неиспользуемого типа служат только для того, чтобы отличать их Request<Foo, Bar>от Request<Foo, Quux>глаз компилятора.

public class Request<T1, T2>
{
    // Common data needed by every GetAsync(), no matter what it returns:
    public string user;
    public string token;

    public Request(string user, string token)
    {
        this.user = user;
        this.token = token;
    }
}

public class Request<T1, T2, T3> : Request<T1, T2>
{
    public Request(string user, string token) : base(user, token) { }
}

Затем методы могут быть перегружены, и каждый может быть создан для возврата типа, соответствующего запросу. (Функции должны быть написаны вручную, но их использование безопасно для типов).

public async Task<Tuple<UserInventory, UserHeroSet>> LoadAsync(
    Request<ServerUserInventory, UserHeroSet> request)
{ ... }

public async Task<Tuple<UserInventory, BattleData>> LoadAsync(
    Request<UserInventory, BattleData> request)
{ ... }

Методы используются следующим образом:

var dbTuple = await LoadAsync(new Request<UserInventory, BattleData>(user, token)).ConfigureAwait(false);
dbTuple.Deconstruct(out UserInventory inventory, out BattleData battleData);
C #, асинхронному Await, перегрузки, метод-перегрузка,
Похожие вопросы