19

I am implementing IListSource that requires a method GetList() with the following signature:

IList GetList()

I am using .NET framework 2 and I'm wanting to return an object that implements IList as follows:

public System.Collections.IList GetList()
{
    return this._mydata; // Implements IList<MyDataRow>            
}

But I get a compile error saying: Cannot implicitly convert type MyData to System.Collections.IList.

If I create a new list of type List<MyDataRow>, populate it and return this list object, then it works. So in other words, this works:

public System.Collections.IList GetList()
{
   List<MyDataRow> list = new List<MyDataRow>();
   foreach (MyDataRow row in this._mydata)
   {
       list.Add(row);
   }
   return list;
}

But it seems very inefficient to have to recreate the list just to get it from type IList<T> to IList. Why is it that I can return a List<MyDataRow>' from 'GetList(), but not an IList<MyDataRow>? Does anyone know of a way for me to return the IList<MyDataRow> without repopulating a new list?

UPDATE:

The _mydata member variable is declared:

private MyData _mydata;

And MyData is declared:

public class MyData : IList<MyDataRow>
{
   ....
}
BruceHill
  • 6,954
  • 8
  • 62
  • 114

5 Answers5

15

Why is it that I can return a List<MyDataRow> from GetList(), but not an IList<MyDataRow>

This is because List<T> implements IList, IList<T> cannot be cast to IList they are 2 separate interfaces. So to answer your question:

Does anyone know of a way for me to return the IList<MyDataRow> without repopulating a new list?

If the concrete type implements IList (which List<T> does) then you can explicitly cast it e.g.

return (IList)this.mydata;

Update

Based on your update, you will have to update MyData to implement IList otherwise you have no choice but to return a new collection which does implement it.

Alternatively, if MyData is indeed a generic list then I would suggest you have it inherit from List<T>, that way you get a lot more flexibility & compatibility out of the box e.g.

class MyData : List<MyDataRow>
{
}
dana
  • 17,267
  • 6
  • 64
  • 88
James
  • 80,725
  • 18
  • 167
  • 237
  • That does explain the problem, but doesn't provide a solution: myData is of type IList, he would still need to call .ToList() and he wants to avoid that. – Louis Kottmann Sep 19 '12 at 13:54
  • @Baboon if `myData` is of type `IList`, but the concrete type is `List` then an explicit cast is all that is needed. – James Sep 19 '12 at 13:57
  • 1
    Thanks, James, for your detailed answer. I am going to give you the credit because the suggestion to inherit from List, rather than encapsulating a List member in my class as I was doing, was indeed the simplest solution to my problem. Thanks for the help. – BruceHill Oct 03 '12 at 12:20
4

The MyData class need to implement the IList along with the generic version IList<T>.

class MyData : IList<MyDataRow>, IList
{
}
Heinzi
  • 167,459
  • 57
  • 363
  • 519
Xharze
  • 2,703
  • 2
  • 17
  • 30
  • +1. I took the liberty of fixing the class name. (According to the OP's error message, the class itself is MyData, not MyDataRow). – Heinzi Sep 19 '12 at 13:53
4

IList<T> does not extend IList, because it's not reasonable to expect every implementation of the generic version to offer the same contract as the non-generic one. If it did extend IList, someone could take the value returned from GetList and reasonably expect to call, e.g. Add(DateTime.Now), or Add(Thread.CurrentThread). That's what IList promises.

That's the reason copying your list to a List<T> works - List<T> implements both interfaces, and throws when its (explicitly implemented) IList methods are called with inappropriate parameter types.

If you can get away with returning IEnumerable, do that instead. If you can return IList<MyDataRow> instead, then do that. If you really need a non-generic IList return, then implement the interface and handle non-MyDataRow values appropriately.

anton.burger
  • 5,637
  • 32
  • 48
4

Either implement IList on your data collection class or create an adapter, which wraps IList<T> and implements IList:

public sealed class NonGenericList<T> : IList
{
    private readonly IList<T> _wrappedList;

    public NonGenericList(IList<T> wrappedList)
    {
        if(wrappedList == null) throw new ArgumentNullException("wrappedList");

        _wrappedList = wrappedList;
    }

    public int Add(object value)
    {
        _wrappedList.Add((T)value);
        return _wrappedList.Count - 1;
    }

    public void Clear()
    {
        _wrappedList.Clear();
    }

    public bool Contains(object value)
    {
        return _wrappedList.Contains((T)value);
    }

    public int IndexOf(object value)
    {
        return _wrappedList.IndexOf((T)value);
    }

    public void Insert(int index, object value)
    {
        _wrappedList.Insert(index, (T)value);
    }

    public bool IsFixedSize
    {
        get { return false; }
    }

    public bool IsReadOnly
    {
        get { return _wrappedList.IsReadOnly; }
    }

    public void Remove(object value)
    {
        _wrappedList.Remove((T)value);
    }

    public void RemoveAt(int index)
    {
        _wrappedList.RemoveAt(index);
    }

    public object this[int index]
    {
        get { return _wrappedList[index]; }
        set { _wrappedList[index] = (T)value; }
    }

    public void CopyTo(Array array, int index)
    {
        _wrappedList.CopyTo((T[])array, index);
    }

    public int Count
    {
        get { return _wrappedList.Count; }
    }

    public bool IsSynchronized
    {
        get { return false; }
    }

    public object SyncRoot
    {
        get { return this; }
    }

    public IEnumerator GetEnumerator()
    {
        return _wrappedList.GetEnumerator();
    }
}

Usage:

public System.Collections.IList GetList()
{
    return new NonGenericList<MyDataRow>(this._mydata);
}
max
  • 33,369
  • 7
  • 73
  • 84
2

If it were possible to convert an IList<T> into an IList directly, you could return a list that could (for example) be "contaminated" with non T objects via its Add(object) method.

David W
  • 10,062
  • 34
  • 60
  • Your second paragraph gets to the crux of it, but the first one seems a little off - the compile error happens precisely because `IList` is *not* derived from `IList`. – anton.burger Sep 19 '12 at 13:56
  • Excellent point. Amended accordingly, and thanks for the correction. You're absolutely right. – David W Sep 19 '12 at 14:01