riffnl
riffnl

Reputation: 3183

Get indexed item from genericlist throws error

I'm trying to get a certain indexed item by number from a generic list and I'm getting: Unable to cast object of type 'System.Collections.Generic.List1[typename]' to type 'System.Collections.Generic.List1[System.Object]'. errors.

What I'm trying to achieve is to loop (forward or backwards) to a certain list based upon a inherited baseclass; like so (or something similar anyway):

public class Fruit
{
  public string Name {get;set;}
}
public class Apple : Fruit
{
  public bool IsSour {get;set;}
}
public class Orange : Fruit
{
  public bool Juicy {get;set;}
}
public List<Apple> Apples = new List<Apple>();
public List<Orange> Oranges = new List<Oranges>();

what I'd like to to is something like this:

public string[] BuildList(object GenericListHere, bool Backwards)
{
  for(int i=GenericListHere.Length-1;i>=0;i--)
  {
    string MyName = GenericListHere[i].Name;

The above is somewhat pseudocoded, but I'd like to throw in either the apples or oranges list to get result. I don't know beforehand which object I'm getting, so I get the Count/Length like this (not psuedocoded) where TestObj is just the object I'm getting:

int iBound = -1;
try
{
    System.Reflection.PropertyInfo oInfo = TestObj.GetType().GetProperty("Count");
    iBound = (int)oInfo.GetValue(TestObj, null);
}
catch
{

And if the iBound >= 0 it's a collection. The next part.. I'm somewhat lost...

 if (iBound != -1)
 {
      int iLoopStart = (backwardsLoop ? iBound - 1 : 0);
      int iLoopEnd = (backwardsLoop ? -1 : iBound);
      int iLoopDifference = (backwardsLoop ? -1 : +1);
      for (int iLoop = iLoopStart; iLoop != iLoopEnd; iLoop += iLoopDifference)
      {
           // THIS IS REALLY BAD CODED.. BUT I DONT GET IT
           object VarCollection = TestObj;
           object[] arInt = new object[1];
           arInt.SetValue(iLoop, 0);
           Type[] tArray = new Type[1];
           tArray.SetValue(typeof(int), 0);
           object oElem = ((System.Collections.Generic.List<object>)VarCollection)[iLoop];

What I'd really like is something like : VarCollection[iLoop], but that doesn't seem to work..

Anyone experienced with these kind of lists? TIA!

Upvotes: 1

Views: 385

Answers (3)

Ani
Ani

Reputation: 113472

I really think reflection isn't the answer here; generics should be more than enough for your needs. It also appears that you don't actually need to access elements from the list by index since the intention appears to simply be to project a sequence of fruits to a sequence of fruit-names. If you do need to access elements by index however (e.g. if you stick with your for loop), it shouldn't be an issue if you use generics; the indexer on IList<T> as well as its Countproperty is easily discoverable in generic code.

The following solution, which uses a generic constraint, should work fine in .NET 3.5:

public static string[] BuildList<T>(IList<T> list, bool backwards) 
    where T : Fruit
{
  var names = list.Select(fruit => fruit.Name);
  return (backwards ? names.Reverse() : names).ToArray();
}

In .NET 4.0, a List<Apple> is correctly recognized as anIEnumerable<Fruit>. Consequently, the following signature should work too:

public static string[] BuildList(IEnumerable<Fruit> list, bool backwards) 

On another note, you might want to consider returning an IEnumerable<string>instead, and let the caller push the results into an array if it so desires.

Upvotes: 1

Marc Gravell
Marc Gravell

Reputation: 1064254

In the case where you are having to work with object and reflection, you should probably simply use the non-generic IList / ICollection interfaces rather than the generic IList<T> / ICollection<T> / List<T>; you will still have indexer, iterate, add, etc

Upvotes: 0

leppie
leppie

Reputation: 117360

Just cast it to IList and use the indexer.

Upvotes: 0

Related Questions