C#- 在任务异步调用上返回 IEnumerable<object>

Posted

技术标签:

【中文标题】C#- 在任务异步调用上返回 IEnumerable<object>【英文标题】:C#- return IEnumerable<object> on task async call 【发布时间】:2019-08-17 04:45:00 【问题描述】:

我有以下代码:

public class TardiisServiceAsync

    private static TardiisServiceAsync instance;

    public static TardiisServiceAsync Instance
    
        //Singleton
        get
        
            if (instance == null)
            
                instance = new TardiisServiceAsync();
            
            return instance;
        
    
    public const string CACHE_PREFIX_TARDIIS_SERVICE = "TardiisServiceAsync_";
    public static Dictionary<string, Tuple<string, object>> clients = new Dictionary<string, Tuple<string, object>>();
    public delegate Task<IEnumerable<object>> GetServiceList(object client, string connectionId, TardiisServiceParameters parameters = null);


    public async Task<IEnumerable<object>> GetDemographicGroupsDelegateAsync(object client, string connectionId, TardiisServiceParameters parameters = null)
    
        //Returns IEnumerable<object> task
        var test = Convert(client.GetType().GetMethod("GetDemographicGroupsAsync").Invoke(client, new object[]  connectionId ));
        var result = await test;
        return (IEnumerable<object>)result;
    

    public async Task<IdNameObject[]> GetDemographicGroupsAsync()
    
        //This task is called from hight level class
        Task<IdNameObject[]> cacheValue = null;
        string cacheKey = CACHE_PREFIX_TARDIIS_SERVICE + Membership.GetUser().UserName + "GetDemographicGroupsAsync" + GetMarketCode();

        if (ConfigurationManager.AppSettings[ConstantsHelper.FIELD_CONFIG_USE_CACHE_KEY] != null && bool.Parse(ConfigurationManager.AppSettings[ConstantsHelper.FIELD_CONFIG_USE_CACHE_KEY]))
        
            if (HttpContext.Current.Cache[cacheKey] == null)
            
                var taskResult = InitializeTardiisInstanceAndCallService(GetDemographicGroupsDelegateAsync);
                var test = await taskResult;
                cacheValue = (Task<IdNameObject[]>)HttpContext.Current.Cache[cacheKey];//This is not implemented yet
             
        

        return await cacheValue;
    

    public static Task<T> Convert<T>(T value)
    
        return Task.FromResult<T>(value);
    

    public static EnumHelper.EnumMarketCode GetMarketCode(EnumHelper.EnumMarketCode? marketCode = null)
    
        //Returns market code
        if (!marketCode.HasValue)
            return (EnumHelper.EnumMarketCode.US);
        else
            return marketCode.Value;
    

    private Task<IEnumerable<object>> InitializeTardiisInstanceAndCallService(GetServiceList getServiceList, TardiisServiceParameters parameters = null, EnumHelper.EnumMarketCode? marketCode = null, bool creatingConnectionsForAllCountries = false, string username = "")
    
        //Get the instance and call the tardiis correct tardiis service depends on the market code
        marketCode = GetMarketCode(marketCode);
        MembershipUser membershipUser = Membership.GetUser();
        string currentUsername = (membershipUser != null ? membershipUser.UserName : username);
        string currentKey = currentUsername + "_" + marketCode;

        if (clients.ContainsKey(currentKey))
        
            try
            
                //check if the connection is still active, or we should reconnect.
                return getServiceList(clients[currentKey].Item2, clients[currentKey].Item1, parameters);
            
            catch (Exception)  
        
        //At this point there is no connection, we need to open it.                            
        object client = TardiisServiceFactory.GetService(marketCode.Value);

        UserDTO userDTO = UserService.Instance.GetByUsername(currentUsername);
        TardiisUserDTO tardiisUserDTO = UserService.Instance.GetTardiisUserByUserIdAndMarketCode(userDTO.ID, marketCode.Value.ToString());

        if (tardiisUserDTO.TardiisUsername == null)
        
            if (creatingConnectionsForAllCountries)
                return null;
            else
                throw new TardiisLoginException("Please enter your credentials");
        

        object user = TardiisServiceFactory.GetUser(marketCode.Value, tardiisUserDTO.TardiisUsername, tardiisUserDTO.TardiisPassword);
        string connectionId;
        try
        
            connectionId = (string)client.GetType().GetMethod("InitConnection").Invoke(client, new object[]  user );
        
        catch (FaultException ex)
        
            // This exception is catched globally by BaseController and prompts the user to enter his
            // tardiis credentials again
            throw new TardiisLoginException(ex.InnerException.Message, ex);
        
        catch (TargetInvocationException ex)
        
            // This exception is catched globally by BaseController and prompts the user to enter his
            // tardiis credentials again
            throw new TardiisLoginException(ex.InnerException.Message, ex);
        

        clients[currentKey] = new Tuple<string, object>(connectionId, client);
        return getServiceList(clients[currentKey].Item2, clients[currentKey].Item1, parameters);
    

    private void AddToCache(string key, object value)
    
        HttpContext.Current.Cache.Add(key, value, null, DateTime.Now.AddMinutes(30), Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);
    


我收到以下错误消息:

无法将“System.Threading.Tasks.Task[System.Object]”类型的对象转换为“System.Collections.Generic.IEnumerable1[System.Object]”类型。

任务的结果是TypedClass[]

如何在调用方法上以Task&lt;IEnumerable&lt;object&gt;&gt; 的形式返回。

这是另一个具有相似逻辑但以同步方式的类的“副本”。这个想法是改变一些方法 所以它们可以同步运行。

谢谢!

【问题讨论】:

var taskResult = task.Result;当您添加 .result 时,这不是一项任务,它将是您使用的可枚举或其他类型 嗨@Pliskin,感谢您的回复,我明白这一点,但我无法将Task&lt;MyCustomClass&gt; 结果转换为Task&lt;IEnumerable&lt;object&gt;&gt;。谢谢。 taskResult的类型和convert方法的param类型是什么? 结果是Task&lt;TardiisPlanning.TardiisPlanningService.DemographicGroup[]&gt;一个自定义类数组。下面我留下 Convert 方法的代码:public static Task&lt;T&gt; Convert&lt;T&gt;(T value) return Task.FromResult&lt;T&gt;(value); 检查更新的代码,让我知道它是否有效,或者将其添加为 Convert resultado.ToList() 的参数 【参考方案1】:
    public async Task<IEnumerable<object>> GetDemographicGroupsDelegateAsync(object client, string connectionId, TardiisServiceParameters parameters = null)


    var test = Convert(client.GetType().GetMethod("GetDemographicGroupsAsync").Invoke(client, new object[]  connectionId ));
    var result = await test;
    var resultado = test.Result;
    return Convert(new List<Object>resultado);

【讨论】:

【参考方案2】:

如果您有 IEnumerable&lt;A&gt; 之类的数组,您可以使用 Linq-Methode Cast&lt;object&gt;() 将其转换为 IEnumerable&lt;object&gt;

public async Task<IEnumerable<object>> GetDemographicGroupsDelegateAsync(object client, string connectionId, TardiisServiceParameters parameters = null)


    var test = Convert(client.GetType().GetMethod("GetDemographicGroupsAsync").Invoke(client, new object[]  connectionId ));
    var task = await test;
    var taskResult = await task;
    return taskResult.Cast<object>();

【讨论】:

嗨,Ackdari,谢谢,但变量 taskResullt 是一个对象类型,不是 awatiable,我说的对吗? @MarceloArias 好吧,我不知道你的对象是什么类型的?如果您告诉我test 的类型和task 的类型是什么,我可能会澄清我的答案。

以上是关于C#- 在任务异步调用上返回 IEnumerable<object>的主要内容,如果未能解决你的问题,请参考以下文章

异步IO和协程

linq查询中的异步任务方法问 题在c#中返回

单线程多任务异步抓取(asyncio)

15.6.2Task使用 组合异步操作

Spring Boot中使用@Async实现异步调用,加速任务的执行!

Spring Boot中使用@Async实现异步调用,加速任务的执行!