Мой код выполняется в правильном порядке?

У меня есть следующий код, и я хочу, чтобы он выполнялся в правильном порядке, но я не уверен, правильно ли я использую «ожидание», чтобы он выполнялся в правильном порядке.

Правильная последовательность должна быть:

1) Вызовите GetTiltleData и получите CurrentCatalogVersion.

2) Вызовите GetCatalogData, чтобы получить ItemID предмета, который будет куплен.

3) Позвоните в MakePurchase, чтобы купить товар.

4) Вызовите GetInventoryList, чтобы получить текущий (после покупки) инвентарь игрока.

Правильно ли я использую ожидание? Выполняется ли мой код в правильном порядке или код может быть выполнен в неправильном порядке?

Например, возможно ли, что код GetCatalogData(); выполняется до CurrentCatalogVersion = result.Result.Data["Catalogversion"]; ?

string CurrentCatalogVersion = "";
string ItemID = "";
int CurrentAmount = 0;

GetTiltleData();
GetCatalogData();

public async void GetTiltleData()
{
    await ClientGetTitleData();
}

private async Task ClientGetTitleData()
{
    var result = await PlayFabClientAPI.GetTitleDataAsync(new GetTitleDataRequest());

    if (result.Result.Data == null || !result.Result.Data.ContainsKey("Catalogversion"))
        Console.WriteLine(result.Error.GenerateErrorReport());
    else
        CurrentCatalogVersion = result.Result.Data["Catalogversion"];
}

public async void GetCatalogData()
{
    await GetCatalog();
}

private async Task GetCatalog()
{
    var result = await PlayFabClientAPI.GetCatalogItemsAsync(new GetCatalogItemsRequest()
    {
        CatalogVersion = CurrentCatalogVersion
    });

    foreach (var entry in result.Result.Catalog)
    {
        //For example, if you want to purchase a sword
        if (entry.DisplayName == "Sword")
            ItemID = entry.ItemId;
    }

    if (result.Error != null)
    {
        Console.WriteLine(result.Error.GenerateErrorReport());
    }
    else
    {
        Console.WriteLine("Listed items successful!");
        await MakePurchase(ItemID);
    }
}


private async Task MakePurchase(string itemid)
{
    var result = await PlayFabClientAPI.PurchaseItemAsync(new PurchaseItemRequest()
    {
        CatalogVersion = CurrentCatalogVersion,
        ItemId = ItemID,
        Price = 100,
        VirtualCurrency = "GO"
    });

    if (result.Error != null)
    {
        Console.WriteLine(result.Error.GenerateErrorReport());
    }
    else
    {
        Console.WriteLine("Purchase successful!");
        await GetInventoryList();
    }
}

private async Task GetInventoryList()
{
    var result = await PlayFabClientAPI.GetUserInventoryAsync(new GetUserInventoryRequest());
    //Get the current amount of the player's virtual currency after the purchase
    CurrentAmount = result.Result.VirtualCurrency["GO"];

    foreach (var entry in result.Result.Inventory)
    {
        //Get a list with the player's items after the purchase
        Console.WriteLine($"{entry.DisplayName} {entry.UnitPrice} {entry.ItemId} {entry.ItemInstanceId}");
      ...
    }

    if (result.Error != null)
    {
        // Handle error if any
        Console.WriteLine(result.Error.GenerateErrorReport());
    }
    else
    {
        Console.WriteLine("Got current inventory");
    }
}

Примечания: 1) Почему у вас есть метод с именем Get*, если он не возвращает никаких данных? 2) Возможно, вы захотите переименовать все методы, которые являются асинхронными, чтобы они заканчивались словом «асинхронный», например GetTiltleDataAsync, чтобы не забыть дождаться его. 3) Избегайте использования async void в сигнатуре метода — вместо этого используйте async Task.

gunr2171 20.06.2019 17:41

1. Если вы собираетесь использовать async/await, вам нужно сделать это во всем стеке вызовов. 2. Все методы (за исключением обработчиков событий, таких как в winforms/wpf) должны иметь возвращаемый тип Task или Task<T>, если они используют await/async.

Igor 20.06.2019 17:46
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
108
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

For example, is it possible that the code of GetCatalogData(); is executed before CurrentCatalogVersion = result.Result.Data["Catalogversion"]; ?

Да, конечно.

Это ваш код вызова:

...
GetTiltleData();
GetCatalogData();

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

Это означает, что у вас есть состояние гонки. Буквально у вас есть 2 потока, спешащих закончить свои методы раньше другого. У вас нет гарантии, какой из них завершится первым или как ЦП расставит приоритеты для своих инструкций. Из-за того, как вы назвали эти методы, вы, по сути, сообщили компьютеру тебе все равно об исходе событий.

Самый быстрый способ убедиться, что один метод завершится до запуска следующего, — это await их обоих. Как говорит Игорь, если вы собираетесь использовать асинхронные методы, вы должны использовать async/await весь путь вверх и вниз по стеку вызовов.

string CurrentCatalogVersion = "";
string ItemID = "";
int CurrentAmount = 0;

await GetTiltleData(); // adding "await" to these 2 lines
await GetCatalogData();

Кроме того, ПОЖАЛУЙСТА, не используйте async void в своих подписях методов. Вместо этого вы должны использовать async Task. См. async/await — когда возвращать Task, а не void?.

Что вы имеете в виду под «использовать async/await на всем пути вверх и вниз по стеку вызовов»? Как должен выглядеть мой код?

John S. 20.06.2019 18:10

Метод, вызывающий асинхронный метод, сам должен быть асинхронным.

gunr2171 20.06.2019 18:11

Этот код не правильный? Оба метода используют слово «асинхронный». Или это не то, что вы имеете в виду? общедоступная асинхронная задача GetTiltleDataAsync() { await ClientGetTitleDataAsync(); } частная асинхронная задача ClientGetTitleDataAsync() { ... }

John S. 20.06.2019 18:35

Вы правы в том, что используете ключевое слово awaitвнутри метода GetTiltleData. А вот код который звонитGetTiltleData не использует await.

gunr2171 20.06.2019 18:36

Ok. Итак, следующий код будет правильным или нет? GetTiltleDataAndGetCatalogDataAsync(); общедоступная асинхронная задача GetTiltleDataAndGetCatalogDataAsync() { await ClientGetTitleDataAsync(); ожидайте GetCatalogAsync(); }

John S. 20.06.2019 18:49

Другие вопросы по теме