简体   繁体   English

如何从另一个 class 调用这种类型的扩展方法

[英]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.

相关问题 我如何从另一个类调用按钮单击方法 - how can i call a button click method from another class 为什么我不能从扩展类型的基础 class 调用扩展方法? - Why can't I call an extension method from a base class of the extended type‏? 我可以从泛型类中调用扩展方法吗? - Can I call an extension method from inside a generic class? 我如何获得一个采用通用类型的类,以从该类型的实例中调用方法? - How can I get a class that takes generic type, to call a method from an instance of that type? 我可以从ASPX页面中的另一个类调用方法吗? - Can I call a method from another class in an ASPX page? 如何确保类可以在另一个类上调用方法,但其他类不能调用该方法? - How do I ensure a Class can call a method on another Class, but not other Classes can call that method? 如何调用异步任务类型的方法 <IHttpActionResult> 来自另一个项目? - How can I call a method of type async Task<IHttpActionResult> from another project? 如何在当前对象上调用另一个类的方法? - How can I call a method on the current object to another class? 属性在另一个类中更改后如何调用方法? - How can I call a method after a property changes in another class? 如何在其类之外调用另一个方法? - How can I call another method outside of its class?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM