Change overridden member to async

╄→гoц情女王★ 提交于 2021-02-16 05:56:46

问题


I am overriding a method in a base class library. However, inside my overridden implementation I am using the new HttpClient which is all based on async methods. I therefore have to mark my method as async, which means that I need to change the return parameter of the method from string to Task. The compiler however gives an error: "The return type must be 'string' to match overridden member ...."

    public class BaseClass
    {
        public virtual string GetName()
        {
            ...
        }
    }

    public class MyClass : BaseClass
    {
        public override async Task<string> GetName()
        {
            HttpClient httpClient = new HttpClient();
            var response = await httpClient.GetAsync("");
            if (response.IsSuccessStatusCode)
            {
                var responseContent = response.Content;

                return await responseContent.ReadAsStringAsync();
            }

            return null;
        }
    }

Of course the obvious solution would be to change the return type of GetName() in BaseClass to Task<string>, but I have no control over BaseClass as it is an external library;

My current solution is to use the HttpClient classes in a synchronous fashion, i.e. change MyClass as follows:

    public class MyClass : BaseClass
    {
        public override string GetName()
        {
            HttpClient httpClient = new HttpClient();
            var response = httpClient.GetAsync("");
            if (response.Result.IsSuccessStatusCode)
            {
                var responseContent = response.Result.Content;

                return responseContent.ReadAsStringAsync()
                                                       .Result;
            }

            return null;
        }
    }

Is there any other way to do this?


回答1:


Unfortunately there isn't a good solution here. There is no way to override a non-async method with an async one. I think your best bet is to have an async non-override method and call into that from the non-async one:

public class MyClass : BaseClass 
{
    public override string GetName() 
    {
        return GetNameAsync().Value;
    }

    public async Task<string> GetNameAsync() 
    { 
        ...
    }
}

Note that this can cause problems though. If the original code didn't expect for any async code to be executing introducing this pattern could break expectations. I would avoid it if possible.




回答2:


Luckily the ReadAsStringAsync().Result is not causing a deadlock since it is likely to have ConfigureAwait(false) within.

To prevent a deadlock, you could use one of the following methods:

public static T GetResult<T>(Func<Task<T>> func)
{
    var httpContext = HttpContext.Context;

    var proxyTask = Task.Run(() =>
    {
        HttpContext.Context = httpContext;
        return func();
    });

    return proxyTask.Result;
}

// or

public static T GetResult<T>(Func<Task<T>> func)
{
    var syncContext = SynchronizationContext.Current;
    SynchronizationContext.SetSynchronizationContext(null);

    var task = func();

    SynchronizationContext.SetSynchronizationContext(syncContext);

    return task.Result;
}

This way you would call

public override string GetName()
{
    ...
    return GetResult(() => responseContent.ReadAsStringAsync());
    ...
}

The former has a performance overhead by spawning a new thread, while the latter suffers from breaking SynchronizationContext flow, which makes any context bound to it unavailable in the task being called, e.g. HttpContext.Current.




回答3:


I've also had this problem, and the solution was using an interface, in which 'async' isn't part of the method's signature.

public abstract class Base : IInvokable {
    /* Other properties ... */

    public virtual async Task Invoke() {
        /*...*/
    }
}

public interface IInvokable {
    Task Invoke();
}

public class Derived 
{
    public override async Task Invoke() {
        // Your code here
    }
}


来源:https://stackoverflow.com/questions/15317961/change-overridden-member-to-async

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!