Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot Convert Type System.Collection.Generic.List<T>

Tags:

c#

generics

I am trying to use generics to reduce my codebase, but ran into this situation. I can't seem to successfully create a google query that expresses what I am trying to do.

In essence I am passing in a Generic to make a List<T> and then pass that List<T> into a function that requires a List<SpecificClass>

My JSONUser class

    public class JSONUser
    {
        public string DocumentId { get; set; }
        [JsonProperty(PropertyName = "UserName", Required = Required.Always)]
        public string UserName { get; set; }
        [JsonProperty(PropertyName = "FirstName", Required = Required.AllowNull)]
        public string FirstName { get; set; }
        [JsonProperty(PropertyName = "LastName", Required = Required.AllowNull)]
        public string Lastname { get; set; }
    }

Assume there is a class JSONCompany with company like fields.

Main Code:

static void CollectUserData()
{
     boolean j = GetJSON<JSONUser>();
     boolean k = GetJSON<JSONCompany>();
     ...
}

static boolean GetJSON<T>()
{
   ...
   // Get the JSON in a List
   List<T> oJSON = CallRest<T>();

   // Now depending on the type passed in, call a different
   // Process Function which expects a List<JSONUser> or
   // List<JSONCompany> parameter

   if (typeof(T) == typeof(JSONUser))
   {
       boolean result = ProcessUser(oJSON);
       ...
   }
   else if (typeof(T) == typeof(JSONCompany))
   {
       boolean result = ProcessCompany(oJSON);
       ...
   }
...
}

public boolean ProcessUser(List<JSONUser> JSONList)
{
    ...
}

public boolean ProcessCompany(List<JSONCompany> JSONList)
{
    ...
}

Everything is good until I call the ProcessUser(oJSON);

It says there is no method to accept the Generic. When I try to cast it, it says

Cannot Covert Type System.Collection.Generic.List<T> to System.Collection.Generic.List<JSONUser>

Hopefully this is clear.

like image 512
Chris ten Den Avatar asked Oct 30 '22 21:10

Chris ten Den


2 Answers

If ProcessUser et al does not require a list and can work with just an IEnumerable<T> then you can simplify it a bit:

public boolean ProcessUser(IEnumerable<JSONUser> JSONList)
{
    ...
}

public boolean ProcessCompany(IEnumerable<JSONCompany> JSONList)
{
    ...
}

Then just call it with:

boolean result = ProcessUser(oJSON.Cast<JSONUser>());

otherwise you could create a new list:

boolean result = ProcessUser(oJSON.Cast<JSONUser>().ToList());

which may be fine if you're just iteerating/modifying the objects in the list and not the list itself. (adding/removing/sorting/etc.)

like image 61
D Stanley Avatar answered Nov 13 '22 01:11

D Stanley


As OP has indicated that the Process functions need to operate on the lists, here is a second answer to complement my first answer. Based on feedback from OP, this assumes that the purpose of ProcessUser/ProcessCompany was really meant to bulk-upload the list of users/companies to a database, which I will assume to be SQL. In this case, JSONUser and JSONCompany (and his other classes) would likely require different SQL calls to function correctly.

Thus, this code demonstrates iterating over the generic list, still using Interface on the base class to define how that object gets written to the database, and yet still not relying on typeof(T).

public interface IInsertToSql
{
    void InsertToSql(SqlCommand cmd);
}

public class JSONUser : IInsertToSql
{
    public string UserID { get; set; }
    public void InsertToSql(SqlCommand cmd)
    {
        cmd.CommandText = "sp_insertJsonUser";
        cmd.Parameters.AddWithValue("@jsonUserId", UserID);
        // More parameters
        cmd.ExecuteNonQuery();
    }
}

public class JSONCompany : IInsertToSql
{
    public string CompanyID { get; set; }
    public void InsertToSql(SqlCommand cmd)
    {
        cmd.CommandText = "sp_insertJsonCompany";
        cmd.Parameters.AddWithValue("@jsonCompanyId", CompanyID);
        // More parameters....
        cmd.ExecuteNonQuery();
    }
}

void Main()
{
    List<JSONUser> users = GetJSON<JSONUser>();
    List<JSONCompany> companies = GetJSON<JSONCompany>();
    BulkUpload(users);
    BulkUpload(companies);
}

static void BulkUpload<T>(List<T> list)
    where T: IInsertToSql
{
    using(SqlConnection conn = new SqlConnection(""))
    {
        conn.Open();
        foreach(T t in list)
        {
            using (SqlCommand cmd = conn.CreateCommand()) t.InsertToSql(cmd);
        }
    }
}

static List<T> GetJSON<T>()
{
    // OP's code to get the list of items, instead of...
    return new List<T>();
}
like image 35
Michael Bray Avatar answered Nov 13 '22 02:11

Michael Bray