none
return a Task of generic list RRS feed

  • Question

  • Hello, 

    Struggling to get the syntax right for this method which needs to return a List<Task<T>>.  I have the syntax correct in a couple of private methods in the same class but I cannot seem to get it right for the ProcessAPIs method.  (I know, I'm going to rename that method...).    

    So this method (ProcessAPIs) needs to return List<Workload> or List<Event> and several other List<T> going forward. 

    I have tried Task<IEnumerable<T>> and Task<List<T>>

    I commented out the code that calls this until I can get the return type sorted. 

    Be great if someone could point out what I have missed or any other observations on the code as I'm new to generics and async programming. 

    Thanks in advance. 

     


    Thursday, March 12, 2020 9:23 PM

Answers

  • Here is something else to consider.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using EFC.Models;
    using Microsoft.EntityFrameworkCore;
    
    namespace EFC
    {
        public class Example
        {
            public async Task<List<T>> GetData<T>()
            {
                var type = typeof(T);
                if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
                {
                    type = type.GenericTypeArguments[0];
                }
    
                if (type == typeof(Customers))
                {
                    using (var context = new NorthWindAzureContext())
                    {
                        var list = await context.Customers.ToListAsync();
                        return list.Select(item => 
                            item != null ? (T)Convert.ChangeType(item, type) : default(T)).ToList();
                    }
                }
                else if (type == typeof(ContactType))
                {
                    using (var context = new NorthWindAzureContext())
                    {
                        var list = await context.ContactType.ToListAsync();
                        return list.Select(item => 
                            item != null ? (T)Convert.ChangeType(item, type) : default(T)).ToList();
                    }
                }
                else
                {
                    throw new Exception();
                }
            }
        }
    }
    

    Demo

    var example = new Example();
    var custList = await example.GetData<Customers>();
    var contactList = await example.GetData<ContactType>();


    Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

    NuGet BaseConnectionLibrary for database connections.

    StackOverFlow
    profile for Karen Payne on Stack Exchange

    Friday, March 13, 2020 1:39 PM
    Moderator

All replies

  • You are missing a <T> either after the procedure name or in the class declaration.

    public async Task<IEnumerablt<T>> ProcessAPIs<T>(Settings settings, etc, etc)

    Thursday, March 12, 2020 10:10 PM
    Moderator
  • You are missing a <T> either after the procedure name or in the class declaration.

    public async Task<IEnumerablt<T>> ProcessAPIs<T>(Settings settings, etc, etc)

    Facepalm!  Can't believe I missed that :-) 

    So the calling code would be... 

    As you can see I had a few goes.  

    Not exactly sure why I can define events as IEnumerable<> but not List<> or IList<>. 

    Thanks for your help, will try the full thing in the morning. 


    Thursday, March 12, 2020 10:40 PM
  • Seems this would be what you are after


    Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

    NuGet BaseConnectionLibrary for database connections.

    StackOverFlow
    profile for Karen Payne on Stack Exchange

    Thursday, March 12, 2020 10:43 PM
    Moderator
  • Ok one more question.  Now the calling code looks correct my two return statements are wrong. 

    Wondering if learning generic lists and async programming at the same time was a good idea.  

    Thanks 

    Thursday, March 12, 2020 10:48 PM
  • Greetings TRS.

    Are you sure generics are the best option for your situation? Could you instead have Event and Workload implement an interface, then return an IList (or IEnumerable, or List, or whatever) of that interface? It would be miles easier if you could, but it would depend on what you need to use from Event and Workload.

    In my experience there are very rarely genuine cases for using generics, except in things like List<T> which are already available anyway.

    Friday, March 13, 2020 12:51 AM
  • Hi,

    Thank you for posting here.

    The method looks a bit strange.

    For Task <IEnumerable<Event>>, it does not have a method called ToList ().

    If you need a collection, you may modify the return type and then call "enents.Result", which will get IEnumable <Event>.

    Best Regards,

    Timon


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Friday, March 13, 2020 6:08 AM
  • Hi, 

    Not sure what you mean or how to do that if I'm honest.  I'm trying to get a list back to my business layer of type Event, Workload (+ others).  Basically this in the BL 

    IEnumerable<Event> events = await (worker.ProcessAPIs<Event>(settings, credentials, uri, apim));
    to this 

    public async Task<IEnumerable<T>> ProcessAPIs<T>(Settings settings, Credentials creds, string uri, ApiModel apim)
    {
        using (var client = new HttpClient())
        {
            var byteArray = Encoding.ASCII.GetBytes($"{ creds.Key }:{ creds.Value }");
    
            client.DefaultRequestHeaders.Authorization =
                new AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
    
            HttpResponseMessage response = await client.GetAsync(uri);
            if (response.IsSuccessStatusCode)
            {
                switch (apim.Target)
                {
                    case "Data.Event":
                        Task<IEnumerable<Event>> events = await GetEvent(response);
                        //return events.ToList();
                        break;
    
                    case "Data.Workload":
                        Task<List<Workload>> workload = await GetWorkload(response);
                        //return workload;
                        break;
                }
            }
        }
    }

    I don't really want a Task back but as I understand it an async method must return this. 

    If there's an easier/better way then great I will do that. 

    Thanks 

    Friday, March 13, 2020 11:15 AM
  • Hello, 

    'T' does not work in this context

    Friday, March 13, 2020 11:16 AM
  • Here is something else to consider.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using EFC.Models;
    using Microsoft.EntityFrameworkCore;
    
    namespace EFC
    {
        public class Example
        {
            public async Task<List<T>> GetData<T>()
            {
                var type = typeof(T);
                if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
                {
                    type = type.GenericTypeArguments[0];
                }
    
                if (type == typeof(Customers))
                {
                    using (var context = new NorthWindAzureContext())
                    {
                        var list = await context.Customers.ToListAsync();
                        return list.Select(item => 
                            item != null ? (T)Convert.ChangeType(item, type) : default(T)).ToList();
                    }
                }
                else if (type == typeof(ContactType))
                {
                    using (var context = new NorthWindAzureContext())
                    {
                        var list = await context.ContactType.ToListAsync();
                        return list.Select(item => 
                            item != null ? (T)Convert.ChangeType(item, type) : default(T)).ToList();
                    }
                }
                else
                {
                    throw new Exception();
                }
            }
        }
    }
    

    Demo

    var example = new Example();
    var custList = await example.GetData<Customers>();
    var contactList = await example.GetData<ContactType>();


    Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

    NuGet BaseConnectionLibrary for database connections.

    StackOverFlow
    profile for Karen Payne on Stack Exchange

    Friday, March 13, 2020 1:39 PM
    Moderator
  • Greetings again TRS. Sorry for the late response. The weekend happened.

    I won't try to code for your particular case, but instead give you a general example of what I meant without worrying about async and whatever.

    Suppose Events and Workloads have something in common that I want to access, and I want a method to return a list of Events or Workloads so that I can access that common thing. Basically, I want to do this.

    // Where 'Something' can be an Event or a Workload.
    List<Something> list = MyMethod()
    
    foreach(Something s in list)
    {
       s.CommonThing();
    }

    The way to achieve this is to put the common thing into an interface.

    public Interface MyInterface
    {
       void CommonThing();
    }
    
    // Implement MyInterface in the Event class.
    public class Event : MyInterface
    {
       public void CommonThing()
       {
           // Do whatever here.
       }
    
       // Plus whatever other code goes in the class.
    }
    
    // Implement MyInterface in the Workload class.
    public class Workload : MyInterface
    {
       public void CommonThing()
       {
           // Do whatever here.
       }
    
       // Plus whatever other code goes in the class.
    }
    
    
    // Now your method that gets the list can use the interface.
    // No need for generics.
    public List<MyInterface> MyMethod()
    {
       if(Something)
       {
          List<Event> le = new List<Event>();
          // fill in the list here.
    
          return le;
       }
       else
       {
          List<Workload> lw = new List<Workload>();
          // Fill in the list here.
    
          return lw;
       }
    }
    
    
    // Use like so.
    List<MyInterface> list = MyMethod()
    
    foreach(MyInterface mi in list)
    {
       mi.CommonThing();
    }

    Note that CommonThing can be completely different between the two classes, as long as it has the same signature (same name and argument list).

    Sunday, March 15, 2020 11:55 PM