C # - Может ли Список <MyClass>быть легко преобразован в Список <Interface>или аналогичный? - PullRequest
0 голосов
/ 03 декабря 2009

У меня есть DataSource в моем контроле, который всегда равен List<T>, где T должен наследовать от IEntity.

public class MyClass<T> where T : IEntity
{
    public List<T> DataSource
    {
        get;
        set;
    }
}

Теперь, очевидно, вы не можете разыграть List<T> до List<IEntity>, выполнив следующее:

List<IEntity> wontWork = (List<IEntity>)this.DataSource;

Как я могу получить источник данных в виде списка IEntity, при этом все еще имея возможность добавлять и удалять элементы из DataSource? То есть Я мог бы сделать следующее, но удаление из списка, который он возвращает, не приведет к удалению из источника данных:

public List<TOut> GetDataSourceCopyAsUnderlyingType<TOut>()
{

    if (this.DataSource == null)
    {
        return new List<TOut>();
    }
    else
    {

        // Get the list and the enumerator
        IList list = (IList)this.DataSource;
        IEnumerator enumerator = list.GetEnumerator();

        // Build the target list
        List<TOut> targetList = new List<TOut>();

        int i = 0;
        while (enumerator.MoveNext())
        {
            TOut entity = (TOut)list[i];
            targetList.Add(entity);
            i++;
        }

        return targetList;

        }

    }

По сути, мне нужен какой-то способ сделать следующее:

List<IEntity> interfaceList = this.GetDataSourceAsAnotherType<IEntity>();
int dataSourceCount = this.DataSource.Count;   // Equals 5
int interfaceCount = interfaceList.Count;      // Equals 5

interfaceList.RemoveAt(0);
int dataSourceCount = this.DataSource.Count;   // Equals 4
int interfaceCount = interfaceList.Count;      // Equals 4

И просто добавлю, я не против, если это означает, что я должен использовать другой тип вместо списка.

EDIT : Извините, забыл сказать, что я использую .Net2.0 и не могу перейти на .Net 3.5.

Ответы [ 5 ]

5 голосов
/ 03 декабря 2009

Было бы монументально плохой идеей, если бы это было разрешено, вот почему это не так. Я могу добавить любой старый IEntity к List<IEntity>, который взорвется, если этот IEntity не может быть приведен к T. Хотя все Ts являются IEntities, не все IEntities являются Ts.

Это работает с массивами, потому что массивы имеют преднамеренное отверстие подтипа (как они делают в Java). В коллекциях нет отверстия для подтипа.

2 голосов
/ 03 декабря 2009

Что сказал DrPizza, но с большим кодом:

public class ListFacade<TIn, TOut> : IList<TOut> where TIn : TOut
{
    private readonly IList<TIn> innerList;

    public ListFacade(IList<TIn> innerList)
    {
        this.innerList = innerList;
    }

    public int Count
    {
        get { return this.innerList.Count; }
    }

    public bool IsReadOnly
    {
        get { return this.innerList.IsReadOnly; }
    }

    public TOut this[int index]
    {
        get { return this.innerList[index]; }
        set { this.innerList[index] = (TIn)value; }
    }

    public void Add(TOut item)
    {
        this.innerList.Add((TIn)item);
    }

    public void Clear()
    {
        this.innerList.Clear();
    }

    public bool Contains(TOut item)
    {
        return (item is TIn) && this.innerList.Contains((TIn)item);
    }

    public void CopyTo(TOut[] array, int arrayIndex)
    {
        var inArray = new TIn[this.innerList.Count];
        this.innerList.CopyTo(inArray, arrayIndex);
        Array.Copy(inArray, array, inArray.Length);
    }

    public IEnumerator<TOut> GetEnumerator()
    {
        foreach (var item in this.innerList)
        {
            yield return item;
        }
    }

    System.Collections.IEnumerator
        System.Collections.IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }

    public int IndexOf(TOut item)
    {
        return (item is TIn) ? this.innerList.IndexOf((TIn)item) : -1;
    }

    public void Insert(int index, TOut item)
    {
        this.innerList.Insert(index, (TIn)item);
    }

    public bool Remove(TOut item)
    {
        return (item is TIn) && this.innerList.Remove((TIn)item);
    }

    public void RemoveAt(int index)
    {
        this.innerList.RemoveAt(index);
    }

Add, Insert и набор индексаторов будут взорваны, если аргумент не имеет типа TIn.

2 голосов
/ 03 декабря 2009

Создайте класс-оболочку, который легко конвертируется. Непроверенный образец:

public class CastList<TTarget, TOriginal> 
  : IList<TTarget> where TOriginal : TTarget
{
  List<TOriginal> _orig;
  public CastList(List<TOriginal> orig) { _orig = orig; }

  public Add(TTarget item) { _orig.Add(item); }

  public TTarget this[int i] 
  {
    get { return (TTarget)_orig[i]; }
    set { _orig[i] = value; }
  }

  public IEnumerator<TTarget> GetEnumerator() 
  {
     foreach(TOriginal item in _orig)
       yield return (TTarget)item;
  }

  // etc...
}

Манипуляции с исходным списком также будут отражены в оболочке. Чтобы использовать это, просто сконструируйте его с вашим источником данных.

0 голосов
/ 03 декабря 2009

Я тоже за linq, но вы можете сделать это так:

var interfaceList = objectList.Cast<IEntity>();

Что короче и выразительнее.

0 голосов
/ 03 декабря 2009

хорошо, это может быть совершенно неуместно, но как насчет использования немного Linq?

var interfaceList = objectList.ConvertAll<Interface>(o => (Interface)o);

таким образом, вы можете легко привести объектный список. надеюсь, это поможет найти решение ...

...