Mark Ursino
Mark Ursino

Reputation: 31435

Generate a generic list of some given type

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, Type 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)); 
}

Upvotes: 4

Views: 21846

Answers (8)

erikkallen
erikkallen

Reputation: 34401

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

Upvotes: 0

Annabelle
Annabelle

Reputation: 10716

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.

Upvotes: 0

Elisha
Elisha

Reputation: 23770

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.

Upvotes: 0

bytebender
bytebender

Reputation: 7491

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

Upvotes: 26

Elisha
Elisha

Reputation: 23770

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

Upvotes: 5

mdm20
mdm20

Reputation: 4563

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

Upvotes: 3

Mark Seemann
Mark Seemann

Reputation: 233150

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...

Upvotes: 1

Rune FS
Rune FS

Reputation: 21742

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

Upvotes: 0

Related Questions