生成某种给定类型的通用列表

时间:2009-11-03 20:43:05

标签: c# generics

我的朋友正在尝试创建一个给定Type的实用程序函数,并在该函数中创建该类型的通用List。我们在创建该列表时遇到了麻烦:

public static List<T> GetQueryResult(string xpathQuery, Type itemType) {

  // this line does not work:
  List<itemType> lst = new List<itemType>();

  return lst;
}

这有什么简单的解决方案吗?

更新

有没有办法基本上这样做?

List<T> lst = new List<T>(); 
foreach (Sitecore.Data.Items.Item i in items) { 
  lst.Add(new T(i)); 
}

8 个答案:

答案 0 :(得分:22)

public static List<T> GetQueryResult<T>(string xpathQuery/*, Type itemType you don't need this because you specified the Type with T*/) {

  // this line works now:
  List<T> lst = new List<T>();

  return lst;
}

然后你会这样调用这个方法:

List<int> results = GetQueryResult<int>("xpathQuery");

修改

你想做这样的事吗?

List<YourType> lst = items.Select<Sitecore.Data.Items.Item, YourType>(
siteCoreItem => new YourType()
{
   PropertyA = siteCoreItem.PropertyA,
}
);

如果YourType继承自Sitecore.Data.Items.Item,则可以使用Cast:

List<YourType> list = items.Cast<YourType>();

答案 1 :(得分:3)

定义这样的方法:

    public static List<T> GetQueryResult<T>(string xpathQuery)
    {
        List<T> lst = new List<T>();

        // do stuff

        return lst;
    }

并将其称为:

 List<SomeType> items = SomeClass.GetQueryResult<SomeType>("query");

答案 2 :(得分:1)

虽然Elisha的回答向您展示了如何从Type实例创建构造的泛型类型,但它不会对您有所帮助,因为我认为您想要做的事情是不可能的:GetQueryResult方法的签名是非法的,因为T是未指定(除非该方法本身是泛型类型的成员)。

该方法不会按照给定的方式进行编译。

如果您已经知道类型,可以将其更改为

public static List<T> GetQueryResult<T>(string xpathQuery)
{
    var lst = new List<T>();
    return lst;
}

但这可能不是你想要的......

答案 3 :(得分:0)

可以使用反射,例如:

var type = typeof(int); // var type = itemType : put this line to fit the method
var genericListType = typeof(List<>).MakeGenericType(type);
var genericList = Activator.CreateInstance(genericListType);

Assert.IsTrue(genericList is List<int>);

在您的示例中,您是否从返回类型中使用了T?也许没有必要在这里使用反思。

如果你没有将T作为泛型参数,那么你不能将List作为泛型List返回,并且该方法必须返回非泛型类型(如IList而不是List)。

答案 4 :(得分:0)

通用类型参数在编译时被解析,因此要使代码正常工作,您需要将itemType作为类型参数传递或将返回类型更改为IList并使用ELisha给出的解决方案但这意味着丢失类型信息在呼叫网站上

答案 5 :(得分:0)

public static List<T> GetQueryResult<T>(string xpathQuery) {
    List<T> lst = new List<T>();
    return lst;
}
如果你想要静态输入,

是唯一的方法。否则你可以做

public static IList GetQueryResults(string xpathQuery, Type itemType) {
    Type tp = typeof(List<>).MakeGenericType(itemType);
    IList lst = (IList)Activator.CreateInstance(tp);
    return lst;
}

但在这种情况下使用非通用列表可能会更好。

编辑:您在同一篇文章中提到了另一个问题:

创建泛型类型实例的3种方法是

  1. 使用where T:new()约束并使用默认构造函数(对你来说似乎不够好)。
  2. 使用反射。很少有最好的主意。
  3. 指定创建者功能
  4. 像这样:

    public static List<T> GetQueryResults<T>(string xpathQuery, Func<int, T> creator) {
        var result = new List<T>();
        foreach (i in something)
            result.add(creator(i));
        return result;
    }
    

    然后调用它:

    List<int> l = GetQueryResults("something", i => new MyObject(i));
    

答案 6 :(得分:0)

回答更新的问题:

public List<T> GetQueryResult<T>(string xPathQuery)
{
    var items = ;// logic to get items
    var list = new List<T>();
    foreach (Sitecore.Data.Items.Item item in items)
    {
        list.Add((T) Activator.CreateInstance(typeof(T), item));
    }

    return list;
}

我假设T有一个获取Sitecore.Data.Items.Item的构造函数,如果它没有代码将在运行时失败。

必须有一种更安全的方法,如果能够为问题提供更广泛的背景,那就更好了。

答案 7 :(得分:0)

正如其他人所证明的那样,解决任何T更新问题的唯一方法就是反思。但是,如果T仅限于您可以修改的众所周知的类型集,则可以执行此操作:

public interface IItemContainer
{
  void SetItem(Sitecore.Data.Items.Item item);
}

public static List<T> GetQueryResult<T>(string xpathQuery)
  where T : IItemContainer, new() {
  IList<Sitecore.Data.Items.Item> items = GetAListOfItemsSomehow(xpathQuery);

  List<T> result = new List<T>();
  foreach (Sitecore.Data.Items.Item item in items) {
    T obj = new T();
    obj.SetItem(item);
    result.add(obj);
  }

  return result;
}

您要用于T的任何类型都必须实施IItemContainer