Преобразовать из IList <T> в не-общий IList
Я реализую IListSource
, для которого требуется метод GetList()
со следующей сигнатурой:
IList GetList()
Я использую .NET framework 2, и я хочу вернуть объект, который реализует IList следующим образом:
public System.Collections.IList GetList()
{
return this._mydata; // Implements IList<MyDataRow>
}
Но я получаю ошибку компиляции: Cannot implicitly convert type MyData to System.Collections.IList
.
Если я создаю список новый типа List<MyDataRow>
, запомните его и верните этот объект списка, тогда он будет работать. Другими словами, это работает:
public System.Collections.IList GetList()
{
List<MyDataRow> list = new List<MyDataRow>();
foreach (MyDataRow row in this._mydata)
{
list.Add(row);
}
return list;
}
Но кажется очень неэффективным, чтобы воссоздать список, чтобы получить его от типа IList<T>
до IList
. Почему я могу вернуть List<MyDataRow>' from 'GetList()
, но не IList<MyDataRow>
? Кто-нибудь знает, как мне вернуть IList<MyDataRow>
без повторного заполнения нового списка?
UPDATE:
Объявлена членская переменная _mydata
:
private MyData _mydata;
И MyData
объявлен:
public class MyData : IList<MyDataRow>
{
....
}
Ответы
Ответ 1
Почему я могу вернуть List<MyDataRow>
из GetList()
, но не IList<MyDataRow>
Это потому, что List<T>
реализует IList
, IList<T>
не может быть добавлено к IList
, это два отдельных интерфейса. Поэтому, чтобы ответить на ваш вопрос:
Кто-нибудь знает, как мне вернуть IList<MyDataRow>
без повторного заполнения нового списка?
Если конкретный тип реализует IList
(что делает List<T>
), вы можете явно его использовать, например.
return (IList)this.mydata;
Обновление
На основе вашего обновления вам нужно будет обновить MyData
, чтобы реализовать IList
, иначе у вас нет выбора, кроме как вернуть новую коллекцию, которая ее реализует.
В качестве альтернативы, если MyData
действительно является общим списком, я бы предположил, что вы наследуете его от List<T>
, таким образом вы получаете гораздо большую гибкость и совместимость из коробки, например.
class MyData : List<MyDataRow>
{
}
Ответ 2
Класс MyData
должен реализовать IList
вместе с общей версией IList<T>
.
class MyData : IList<MyDataRow>, IList
{
}
Ответ 3
IList<T>
не распространяется IList
, так как неразумно ожидать, что каждая реализация родовой версии предложит тот же контракт, что и не общий. Если бы это расширило IList
, кто-то мог бы взять значение, возвращенное из GetList
, и разумно ожидать вызова, например. Add(DateTime.Now)
или Add(Thread.CurrentThread)
. Это то, что IList
promises.
То, что причина копирования вашего списка в List<T>
works - List<T>
реализует оба интерфейса и выбрасывает, когда его (явно реализованные) методы IList
вызываются с неприемлемыми типами параметров.
Если вы можете уйти с возвратом IEnumerable
, сделайте это вместо этого. Если вы можете вернуть IList<MyDataRow>
вместо этого, сделайте это. Если вам действительно нужен не-общий IList
return, тогда реализуйте интерфейс и обрабатывайте значения не MyDataRow
соответствующим образом.
Ответ 4
Либо внедрите IList
в свой класс сбора данных, либо создайте адаптер, который обертывает IList<T>
и реализует 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();
}
}
Использование:
public System.Collections.IList GetList()
{
return new NonGenericList<MyDataRow>(this._mydata);
}
Ответ 5
Если бы можно было напрямую преобразовать IList<T>
в IList
, вы могли бы вернуть список, который мог бы (например) быть "заражен" объектами не T
через его метод Add(object)
.