不能转换类型System.Collection.Generic.List

本文关键字:List Generic Collection 转换 类型 System 不能 | 更新日期: 2023-09-27 18:08:57

我试图使用泛型来减少我的代码库,但遇到了这种情况。我似乎不能成功地创建一个谷歌查询来表达我想要做的事情。

本质上,我正在传递一个泛型来制作List<T>,然后将List<T>传递到需要List<SpecificClass>的函数

My JSONUser类

    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; }
    }

假设有一个类JSONCompany,其字段类似于company。

主要代码:

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)
{
    ...
}

一切都很好,直到我打电话给ProcessUser(oJSON);

它说没有办法接受泛型。当我试图强制转换它时,它显示

无法将类型System.Collection.Generic.List<T>转换为System.Collection.Generic.List<JSONUser>

不能转换类型System.Collection.Generic.List<T>

如果ProcessUser等不需要列表,并且可以只使用IEnumerable<T>,那么您可以简化一下:

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

然后用:

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

否则可以创建一个新列表:

boolean result = ProcessUser(oJSON.Cast<JSONUser>().ToList());
如果您只是迭代/修改列表中的对象而不是列表本身,则

可能是好的。(添加/删除/排序/等等)。

由于OP已经指出Process函数需要对列表进行操作,因此这里是第二个答案,以补充我的第一个答案。根据OP的反馈,这假设ProcessUser/ProcessCompany的目的实际上是将用户/公司列表批量上传到数据库,我将假设该数据库是SQL。在这种情况下,JSONUser和JSONCompany(以及他的其他类)可能需要不同的SQL调用才能正常工作。

因此,这段代码演示了遍历泛型列表,仍然使用基类上的Interface来定义如何将该对象写入数据库,但仍然不依赖于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>();
}

让特定的函数对特定的泛型类型做特定的事情通常是与泛型的设计思想相违背的。如果你正在检查typeof(T),那么这是一个很好的指示(但不一定是完美的),可能有一个更好的设计。

有几种方法可以完成我认为你正在努力做的事情……这里有一个例子可以让你的大脑朝着正确的方向运动:

如果ProcessUser和ProcessCompany都操作单个对象(即列表项,而不是列表本身),正如方法名称所暗示的那样,那么您可以使JSONUser和JSONCompany都继承于一个接口,例如ICanProcess有一个返回bool值的方法Process()。然后你可以说:

interface ICanProcess
{
    bool Process();
}
class JSONUser : ICanProcess
{
    // implement Process for this object
}
static bool GetJSON<T>()
    where T: ICanProcess
{
    ...
    bool result = true;
    foreach(T it in oJSON)
    {
        // I assume the result should be AND of all items process result
        result = result && it.Process();  
    }
}