开发者

Generate a generic list of some given type

开发者 https://www.devze.com 2022-12-09 23:40 出处:网络
My friend is trying to create a utility function that is given some Type and in that function it creates a generic List of that type. We\'re having trouble creating that list:

My friend is trying to create a utility function that is given some Type and in that function it creates a generic List of that type. We're having trouble creating that list:

public static List<T> GetQueryResult(string xpathQuery, Ty开发者_如何转开发pe itemType) {

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

  return lst;
}

Are there any easy solutions to this?

UPDATE:

Is there any way to basically do this???

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


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

Then you would call the method like so:

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

Edit:

Are you wanting to do something like this?

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

If YourType inherrits from Sitecore.Data.Items.Item you can use Cast:

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


Define that method like this:

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

        // do stuff

        return lst;
    }

and call it like this:

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


It is possible using reflection, for example:

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

In your example, ehere do you get T from that you use in the return type? Maybe there is no need to use here reflection.

If you do not get T as generic argument then you cannot return the List as generic List and the method will have to return a non generic type (like IList instead of List).


While Elisha's answer shows you how you can create a constructed generic type from a Type instance, it's not going to help you because what I think you want to do is not possible: the signature of the GetQueryResult method is illegal because T is unspecified (unless the method is a member of a generic type itself).

The method will not compile as given.

If you already know the type, you can change it to

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

but that's probably not what you want...


Generic type arguments are resolved compile time, so to have the code working you'd need to pass itemType as a type argument or change the return type to IList And Them use the solution given by ELisha but that would mean loosing type information on the Call site


Answer to the updated question:

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

I assume that T has a constructor that gets Sitecore.Data.Items.Item, if it won't have the code will fail at runtime.

There must be a safer way to do it, it'll be better if you can give wider context to the problem.


As others have demonstrated, the only way to solve your updated question for any T is with reflection. However, if T is restricted to a well known set of types that you can modify, you could do this:

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

Any types you want to use for T would then have to implement IItemContainer.


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

is the only way if you want static typing. Otherwise you could do

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

but using a non-generic list would probably be better in that case.

Edit: You asked another question in the same post:

The 3 ways of creating an instance of a generic type are

  1. use the where T : new() constraint and use the default constructor (doesn't seem good enough for you).
  2. Use reflection. Rarely the best idea.
  3. Specify a creator function

like this:

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

and then invoke it like:

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

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号