У меня есть следующий код, и я хочу, чтобы он выполнялся в правильном порядке, но я не уверен, правильно ли я использую «ожидание», чтобы он выполнялся в правильном порядке.
Правильная последовательность должна быть:
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. Если вы собираетесь использовать async/await, вам нужно сделать это во всем стеке вызовов. 2. Все методы (за исключением обработчиков событий, таких как в winforms/wpf) должны иметь возвращаемый тип Task или Task<T>, если они используют await/async.





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 на всем пути вверх и вниз по стеку вызовов»? Как должен выглядеть мой код?
Метод, вызывающий асинхронный метод, сам должен быть асинхронным.
Этот код не правильный? Оба метода используют слово «асинхронный». Или это не то, что вы имеете в виду? общедоступная асинхронная задача GetTiltleDataAsync() { await ClientGetTitleDataAsync(); } частная асинхронная задача ClientGetTitleDataAsync() { ... }
Вы правы в том, что используете ключевое слово awaitвнутри метода GetTiltleData. А вот код который звонитGetTiltleData не использует await.
Ok. Итак, следующий код будет правильным или нет? GetTiltleDataAndGetCatalogDataAsync(); общедоступная асинхронная задача GetTiltleDataAndGetCatalogDataAsync() { await ClientGetTitleDataAsync(); ожидайте GetCatalogAsync(); }
Примечания: 1) Почему у вас есть метод с именем
Get*, если он не возвращает никаких данных? 2) Возможно, вы захотите переименовать все методы, которые являются асинхронными, чтобы они заканчивались словом «асинхронный», напримерGetTiltleDataAsync, чтобы не забыть дождаться его. 3) Избегайте использованияasync voidв сигнатуре метода — вместо этого используйтеasync Task.