BruceHill
BruceHill

Reputation: 7174

Convert from IList<T> to non-generic IList

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

Upvotes: 19

Views: 17674

Answers (5)

James
James

Reputation: 82136

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

Upvotes: 15

David W
David W

Reputation: 10184

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.

Upvotes: 2

max
max

Reputation: 34437

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

Upvotes: 4

anton.burger
anton.burger

Reputation: 5706

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.

Upvotes: 4

Xharze
Xharze

Reputation: 2733

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

class MyData : IList<MyDataRow>, IList
{
}

Upvotes: 4

Related Questions