45

I have written a method which is public List<List<object>> Fetch(string data), inside I create List<List<object>> p = new List<List<object>>();

my boss now wants to return a IList<IList<object>> instead of List<List<object>> ie
public IList<IList<object>> Fetch(string data),

so when I try do return (IList<IList<object>>) p; //throws an exception

How do I convert List<List<object>> to IList<IList<object>> and back to List<List<object>>

A-Sharabiani
  • 17,750
  • 17
  • 113
  • 128
david
  • 485
  • 1
  • 4
  • 10

6 Answers6

93

You can't perform that conversion via straight casting - it wouldn't be safe. Instead, you should use:

IList<IList<object>> ret = new List<IList<object>>();

Then for each "sublist" you can use:

// Or whatever
ret.Add(new List<object>());

Finally, just return ret.

You could use LINQ to perform the conversion of your existing List<List<object>> when you return it - but it would be better to just create a more appropriate type to start with, as shown above.


To understand why some of the existing answers are wrong, suppose you could do this:

IList<IList<object>> p = new List<List<object>>();

Then this would be valid:

List<List<object>> listOfLists = new List<List<object>>();
IList<IList<object>> p = listOfLists;
p.Add(new object[]);
List<object> list = p[0];

But p[0] is a reference to an object[], not a List<object>... our supposedly type-safe code doesn't look as safe any more...

Fortunately, IList<T> is invariant to prevent exactly this problem.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
14

You would have to declare your list as

IList<IList<object>> list = new List<IList<object>>(); // Works!

This works, because only the outer list is created in the first place. You can then insert individual items that are compatible with IList<object>:

list.Add(new List<object>());
list.Add(new object[10]);
Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188
4
var myOriginalList = new List<List<Object>>();
var converted = ((IList<IList<Object>>)myOriginalList.Cast<IList<Object>>().ToList()); // EDIT: Added .ToList() here

You shouldn't need to convert back- you can do just about anything on IList that you could on List.

Chris Shain
  • 50,833
  • 6
  • 93
  • 125
  • 2
    Why bother creating a new list though? It's simpler just to create the right type to start with. – Jon Skeet Jan 25 '12 at 16:19
  • Agreed 100%, and your approach explains that well. I leave this up to show that if you needed to do it (e.g. the off chance a third party library returned a `List>` that you needed to convert for another 3rd party library), you can do it this way. – Chris Shain Jan 25 '12 at 16:21
2

You need to change the declaration of the result variable from List<List<object> to IList<IList<object>>

Which you can instantiate against List<IList<object>>

And each item in the result can be of type List<object>

    static IList<IList<object>> Test()
    {
        IList<IList<object>> result = new List<IList<object>>();
        var item = new List<object>() { "one", "two", "three" };
        result.Add(item);
        return result;
    }
Muhammad Hasan Khan
  • 34,648
  • 16
  • 88
  • 131
1
public IList<IList<object>> Fetch(string data)
{
  IList<IList<object>> p = new List<IList<object>>();

  // add your stuff here

  return p;
}
John Ruiz
  • 2,371
  • 3
  • 20
  • 29
  • @vidstige JonSkeet was correct for about 30 seconds.. I originally had IList> p = new List>(); which would not compile, and shouldn't. I noticed my mistake like 10 seconds after posting. TEN SECONDS. Further proof that JonSkeet is actually a bot. =) I don't know who that was talking to Hanselman the other day... – John Ruiz Jan 25 '12 at 16:43
  • lol thats quick alright. But I cannot see that your post was edited? Perhaps there is some 'quiet time' where you can editit it without beeing a new revision... – vidstige Jan 25 '12 at 17:47
0

List<T> and IList<T> do not support covariance. So this does not compile:

List<List<string>> list = new List<IList<string>>(); // DOES NOT COMPILE!!!!!
Aliostad
  • 80,612
  • 21
  • 160
  • 208
  • `List` is already of Type `IList` No co- (or contra-)variance is required. – AllenG Jan 25 '12 at 16:13
  • 1
    @AllenG so can you explain why that snippet I have put does not compile? – Aliostad Jan 25 '12 at 16:14
  • 2
    @AllenG: Yes, contravariance *is* required here, because a `List>` isn't a `List>`. Did you try to compile the code Aliostad said won't compile? It really won't. – Jon Skeet Jan 25 '12 at 16:15
  • I added my comment before you added your snippet. List> should be a valid return on a Method with a signature of IList>. – AllenG Jan 25 '12 at 16:22
  • @AllenG that still does not justify downvote. The problem OP experiences is the result of lack of covariance/contravariance in ILst and List. – Aliostad Jan 25 '12 at 16:25
  • 5
    @AllenG: No, it absolutely should not. There are too many lists here. Should List be a valid return for a method typed as returning IList? Yes. Should List be a valid return for a method typed as returning IList? **No, absolutely not**. The caller reasonably expects that they can insert a Bottle into an IList but what you have in hand is a List that cannot contain a Bottle. Therefore the conversion must be illegal. – Eric Lippert Jan 25 '12 at 16:35