[英]How can I call this type of extension method from another class
async Task<TResult> CancelAfterAsync<TResult>(Func<CancellationToken, Task<TResult>> startTask, TimeSpan timeout, CancellationToken cancellationToken)
{
using (var timeoutCancellation = new CancellationTokenSource())
using (var combinedCancellation = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutCancellation.Token))
{
var originalTask = startTask(combinedCancellation.Token);
var delayTask = Task.Delay(timeout, timeoutCancellation.Token);
var completedTask = await Task.WhenAny(originalTask, delayTask);
// Cancel timeout to stop either task:
// - Either the original task completed, so we need to cancel the delay task.
// - Or the timeout expired, so we need to cancel the original task.
// Canceling will not affect a task, that is already completed.
timeoutCancellation.Cancel();
if (completedTask == originalTask)
{
// original task completed
return await originalTask;
}
else
{
// timeout
throw new TimeoutException();
}
}
}
Asynchronously wait for Task<T> to complete with timeout 异步等待 Task<T> 超时完成
I found this async method here at stackoverflow and I created an extension method of this method:我在 stackoverflow 找到了这个异步方法,并创建了这个方法的扩展方法:
public static async Task<TResult> CancelAfterAsync<TResult>(this Func<CancellationToken, Task<TResult>> startTask, TimeSpan timeout, CancellationToken cancellationToken)
{
using (var timeoutCancellation = new CancellationTokenSource())
using (var combinedCancellation = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutCancellation.Token))
{
var originalTask = startTask(combinedCancellation.Token);
var delayTask = Task.Delay(timeout, timeoutCancellation.Token);
var completedTask = await Task.WhenAny(originalTask, delayTask);
// Cancel timeout to stop either task:
// - Either the original task completed, so we need to cancel the delay task.
// - Or the timeout expired, so we need to cancel the original task.
// Canceling will not affect a task, that is already completed.
timeoutCancellation.Cancel();
if (completedTask == originalTask)
{
// original task completed
return await originalTask;
}
else
{
// timeout
throw new TimeoutException();
}
}
}
But I don't know how to call this type of extension method in another class.但是我不知道如何在另一个class中调用这种类型的扩展方法。
What is the first parameter CancellationToken and the last parameter cancellationToken in the async method? async方法的第一个参数CancellationToken和最后一个参数cancellationToken是什么?
I want to create a task of the following async method UpdatePlayerCountryData and use it with the extension method to find out if UpdatePlayerCountryData completes in 5 seconds and if not then throw new TimeoutException();.我想创建以下异步方法 UpdatePlayerCountryData 的任务,并将其与扩展方法一起使用来确定 UpdatePlayerCountryData 是否在 5 秒内完成,如果没有则抛出新的 TimeoutException();。 I get an error message because I don't know what the two missing arguments are:
我收到一条错误消息,因为我不知道缺少的两个 arguments 是什么:
Error CS0839: Argument missing
错误 CS0839:缺少参数
var test = await Extensionmethods.CancelAfterAsync( , UpdatePlayerCountryData("Germany", "Berlin"), new TimeSpan(0, 0, 0, 5, 0), );
How can I use UpdatePlayerCountryData with the extension method?如何将 UpdatePlayerCountryData 与扩展方法一起使用? How can I call CancelAfterAsync from another class?
如何从另一个 class 调用 CancelAfterAsync?
private async Task UpdatePlayerCountryData(string country, string city)
{
var resultprofile = await PlayFabClientAPI.UpdateUserDataAsync(new PlayFab.ClientModels.UpdateUserDataRequest()
{
Data = new Dictionary<string, string>() {
{"Country", country},
{"City", city}
},
Permission = PlayFab.ClientModels.UserDataPermission.Public
});
if (resultprofile.Error != null)
Console.WriteLine(resultprofile.Error.GenerateErrorReport());
else
{
Console.WriteLine("Successfully updated user data");
}
}
UPDATE: I changed my code.更新:我改变了我的代码。 Will the method UpdatePlayerCountryData be canceled with token.IsCancellationRequested after 10 seconds(TimeSpan.FromSeconds(10)) or will cancelling not work when await PlayFabClientAPI.UpdateUserDataAsync takes longer than 10 seconds?
方法 UpdatePlayerCountryData 会在 10 秒后使用 token.IsCancellationRequested (TimeSpan.FromSeconds(10)) 取消,还是在 await PlayFabClientAPI.UpdateUserDataAsync 需要超过 10 秒时取消不起作用?
Will (token.IsCancellationRequested) only be executed after await PlayFabClientAPI.UpdateUserDataAsync finished, even if it would take minutes? (token.IsCancellationRequested) 只有在等待 PlayFabClientAPI.UpdateUserDataAsync 完成后才会执行,即使它需要几分钟?
if (token.IsCancellationRequested)
{
return;
}
Complete code:完整代码:
public async Task PlayerAccountDetails()
{
TimeSpan timeout = TimeSpan.FromSeconds(10);
CancellationTokenSource cts = new CancellationTokenSource();
try
{
await UpdatePlayerCountryData("Country", "City", cts.Token).CancelAfter(timeout, cts.Token);
}
catch (Exception ex)
{
//catch exception here for logging
}
}
public static async Task CancelAfter(this Task @task, TimeSpan timeout, CancellationToken token)
{
var timeoutTask = Task.Delay(timeout, token);
var originalTask = @task;
var completedTask = await Task.WhenAny(timeoutTask, originalTask);
if (completedTask == timeoutTask)
throw new TimeoutException();
await completedTask;
}
private static async Task UpdatePlayerCountryData(string country, string city, CancellationToken token)
{
var resultprofile = await PlayFabClientAPI.UpdateUserDataAsync(new PlayFab.ClientModels.UpdateUserDataRequest()
{
Data = new Dictionary<string, string>() {
{"Country", country},
{"City", city}
},
Permission = PlayFab.ClientModels.UserDataPermission.Public
});
if (token.IsCancellationRequested)
{
return;
}
if (resultprofile.Error != null)
Console.WriteLine(resultprofile.Error.GenerateErrorReport());
else
{
Console.WriteLine("Successfully updated user data");
}
}
Please check the code for usage.请检查代码以了解使用情况。 Also cancelafter function posted in your post is one way of doing it.
在您的帖子中发布的 function 之后取消也是一种方法。 Another way of same thing to doing it as follows.
另一种做同样事情的方法如下。 Also for clear understanding cancelling task in this fashion and its consequences here
也为了清楚地了解以这种方式取消任务及其后果
public static class Test
{
private static async Task UpdatePlayerCountryData(string country, string city)
{
var resultprofile = await PlayFabClientAPI.UpdateUserDataAsync(new PlayFab.ClientModels.UpdateUserDataRequest()
{
Data = new Dictionary<string, string>() {
{"Country", country},
{"City", city}
},
Permission = PlayFab.ClientModels.UserDataPermission.Public
});
if (resultprofile.Error != null)
Console.WriteLine(resultprofile.Error.GenerateErrorReport());
else
{
Console.WriteLine("Successfully updated user data");
}
}
public static async Task CancelAfter(this Task @task, TimeSpan timeout,CancellationToken token)
{
var timeoutTask = Task.Delay(timeout, token);
var originalTask = @task;
var completedTask = await Task.WhenAny(timeoutTask, originalTask);
if (completedTask == timeoutTask)
throw new TimeoutException();
await completedTask;
}
//Usage method
public static async Task ExtensionMethodUsage()
{
//Timeout ,for demonstartion purpose i used 10 seconds
//Modify according to your need
TimeSpan timeout = TimeSpan.FromSeconds(10);
//Cancellation Token
CancellationTokenSource cts = new CancellationTokenSource();
//U can manually cancel the task here if a caller of the function
//does not want to wait for timeout to occur.
//Some mechanism to cancel the task.
// If dont have a provision to cancel the task(which is not a good pattern)
//There is no need to use cancellation token
cts.Cancel();
try
{
//Pass the cancellation token to method
//When Cancel() is called all task will be cancalled.
await UpdatePlayerCountryData("Country", "City",cts.Token).CancelAfter(timeout, cts.Token);
}
catch (Exception)
{
//catch exception here for logging
}
}
}
Usage of cancellation token is incorrect.取消令牌的使用不正确。 Correct usage would be something like this
正确的用法是这样的
private static async Task UpdatePlayerCountryData(string country, string city, CancellationToken token)
{
// UpdateUserDataAsync should take the Cancellation token,
// but I am afraid this method has any provision.
var resultprofile = await PlayFabClientAPI.UpdateUserDataAsync(new PlayFab.ClientModels.UpdateUserDataRequest()
{
Data = new Dictionary<string, string>() {
{"Country", country},
{"City", city}
},
Permission = PlayFab.ClientModels.UserDataPermission.Public
});
// Yes it would execute after the above await is complete
if (token.IsCancellationRequested)
{
return;
}
if (resultprofile.Error != null)
Console.WriteLine(resultprofile.Error.GenerateErrorReport());
else
{
Console.WriteLine("Successfully updated user data");
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.