C#泛型方法无法创建List <t>

时间:2015-05-12 13:04:01

标签: c# generics generic-list

我有一个界面和两个类。

public interface IMyInterface { }
public class A : IMyInterface { }
public class B : IMyInterface { }

我有一个通用的方法,

private List<T> GetList<T>(DataTable table) 
            where T : class, IMyInterface
{
    ...
}

应根据DataTable中的数据返回一个对象列表。所以,我在这个方法中创建了一个列表,我想在最后返回。我以为我可以做到以下几点,

private List<T> GetList<T>(DataTable table)
           where T : class, IMyInterface
{
   List<T> myList = new List<T>;

   // Now I thought I could easily add Objects based on T because,
   // both classes implement the interface

   if (typeof(T) == typeof(B))
   {
      myList.Add(new B());
   }
   else
   {
      myList.Add(new A());
   }

   return myList;
}

但是编译器告诉我“参数类型A(B)不是可以指定的”!为什么不可分配?

好的,我也可以这样做,

private List<T> GetList<T>(DataTable table)
           where T : class, IMyInterface
{
   List<IMyInterface> myList = new List<IMyInterface>;

   // Now I can assign the Object's :)
   if (typeof(T) == typeof(B))
   {
      myList.Add(new B());
   }
   else
   {
     myList.Add(new A());
   }

   return myList as List<T>;
}

编译器没有抱怨,但return子句的结果始终为null。确保myList中有值。演员似乎失败了。有人请帮我更优雅地解决这个问题。

7 个答案:

答案 0 :(得分:5)

一种方法是添加new()约束。限制是您需要类型参数T的公共无参数构造函数。

private static List<T> GetList<T>(DataTable table) where T : class, IMyInterface, new()
{
    List<T> myList = new List<T>();
    T instance = new T();
    //access anything defined in `IMyInterface` here
    myList.Add(instance);
    return myList;
}

答案 1 :(得分:2)

我不明白你在这里要做什么。为什么你甚至需要泛型?

你最初是以正确的方式,从同一个界面派生你的类型,所以要使用它。声明您的列表List<IMyInterface>,只需按原样添加对象即可。

如果以后你实际上需要具有具体AB类型的可枚举的物理表示,那么你有OfType<>()Cast<>(),尽管它显示了你的多态性首先做错了。

答案 2 :(得分:1)

添加new constraint

private List<T> GetList<T>(DataTable table) where T : class, IMyInterface, new()
{
   return new List<T>(){ new T() };
}

答案 3 :(得分:1)

在将对象添加到List:

之前,您应该先强制转换对象
 private static List<T> GetList<T>(DataTable table) where T : class, MyInterface
    {
        List<T> myList = new List<T>();

        //Now i thought i can easily add Objects based on T, because both classes
        //implement the interface
        if (typeof (T) == typeof (B))
        {
            // use of 'as' operator
            myList.Add(new B() as T);
        }
        else
        {
            myList.Add(new A() as T);
        }

        return myList;
    }

但无论如何,我没有得到一点,你想要实现的目标。

同样myList as List<T>肯定会产生null,因为您无法使用as运算符强制转换通用集合,因为List<T>未声明为Covariant。您应该明确调用.Cast<T>()方法来创建新集合。

答案 4 :(得分:1)

我猜你真的想做点什么,

public IList<T> GetList<T>(
        DataTable table,
        Func<DataRow, T> extractor)
{
    var result = new T[table.Rows.Count];
    for (var i = 0; i < table.Rows.Count; i++)
    {
        result[i] = extractor(table.Rows[i]);
    }

    return result;
}

extractor是将DataRow转换为T的代表。

这比你想象的更简单,

// referencing System.Data.DataSetExtensions

var list = GetList(
        data,
        row => new A
            {
                Id = row.Field<int>("id"),
                ...
            });

list将是IList<A>等其他类型。

答案 5 :(得分:0)

试试这个:

private List<T> GetList<T>(DataTable table) where T : class, IMyInterface {
   List<T> myList = new List<T>();
   if (typeof(T) == typeof(B)) {
      myList.Add((T)new B());
   }
   else {    
     myList.Add((T)new A());
   }
   return myList
}

答案 6 :(得分:0)

仅适用于A类和B类

 static List<T> GetList<T>(DataTable table) where T : class, IMyInterface
        {
            List<T> myList = new List<T>();

            IMyInterface obj;
            if (typeof(T) == typeof(B))
            {
                obj = new B();
            }
            else
            {
                obj = new A();
            }

            myList.Add((T)obj);

            return myList;
        }