Подтвердить что ты не робот

С# Листинг списка <ObjBase> как List <Obj>

Почему я не могу отличить List<ObjBase> как List<Obj>? Почему не работает следующее:

internal class ObjBase
   {
   }

internal class Obj : ObjBase
   {
   }   

internal class ObjManager
{
    internal List<Obj> returnStuff()
    {
       return getSomeStuff() as List<Obj>;
    }

    private List<ObjBase> getSomeStuff()
    {
       return new List<ObjBase>();
    }

}

Вместо этого я должен сделать это:

internal class ObjBase
   {
   }

internal class Obj : ObjBase
   {
   }

internal class ObjManager
{
    internal List<Obj> returnStuff()
    {
       List<ObjBase> returnedList = getSomeStuff();
       List<Obj> listToReturn = new List<Obj>(returnedList.Count);
       foreach (ObjBase currentBaseObject in returnedList)
       {
          listToReturn.Add(currentBaseObject as Obj);
       }
       return listToReturn;
    }

    private List<ObjBase> getSomeStuff()
    {
       return new List<ObjBase>();
    }
}

Я получаю следующую ошибку в Visual Studio 2008 (сокращенную для удобочитаемости):

Невозможно преобразовать тип "Список" в "Список" через ссылочное преобразование, преобразование бокса, преобразование распаковки, конвертирование конверсий или преобразование нулевого типа.

Спасибо.

4b9b3361

Ответ 2

Вы можете использовать методы расширения Cast и ToList из System.Linq, чтобы иметь это в одной строке.

Вместо

internal List<Obj> returnStuff()
{
   return getSomeStuff() as List<Obj>;
}

сделайте следующее:

internal List<Obj> returnStuff()
{
   return getSomeStuff().Cast<Obj>().ToList();
}

Ответ 3

Я могу описать "проблему" только из представления Java, но из того, что мало знаю, этот аспект одинаковый как для С#, так и для Java:

A List<ObjBase> не является List<Obj>, поскольку он может содержать объект ObjBase, который не является объектом Obj.

Другой способ List<Obj> не может быть добавлен к List<ObjBase>, потому что первый гарантирует прием вызова Add() с аргументом ObjBase, который последний не примет!

Итак, суммируем: хотя Obj is-a ObjBase a List<Obj> не является List<ObjBase>.

Ответ 5

Я думаю, вы неправильно понимаете, какой бросок вы пытаетесь сделать. Вы думаете, что вы изменяете тип объекта, который хранится в списке, где вы на самом деле пытаетесь изменить тип самого списка. Скорее имеет смысл, что вы не можете изменить сам список, поскольку вы уже заселили его.

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

Какова цель этой попытки?

Ответ 6

В настоящее время С# не поддерживает дисперсию для общих типов. Из того, что я прочитал, это изменится в 4.0.

См. здесь для получения дополнительной информации о дисперсии в дженериках.

Ответ 7

list.ConvertAll выглядит заманчиво, но имеет 1 большой недостаток: он создаст новый список. Это будет влиять на производительность и использование памяти, особенно для больших списков.

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

Использование:

var x = new List<ObjBase>();
var y = x.CastList<ObjBase, Obj>(); // y is now an IList<Obj>

Код для добавления в вашу библиотеку:

public static class Extensions
{
    public static IList<TTo> CastList<TFrom, TTo>(this IList<TFrom> list)
    {
        return new CastedList<TTo, TFrom>(list);
    }
}

public class CastedList<TTo, TFrom> : IList<TTo>
{
    public IList<TFrom> BaseList;

    public CastedList(IList<TFrom> baseList)
    {
        BaseList = baseList;
    }

    // IEnumerable
    IEnumerator IEnumerable.GetEnumerator() { return BaseList.GetEnumerator(); }

    // IEnumerable<>
    public IEnumerator<TTo> GetEnumerator() { return new CastedEnumerator<TTo, TFrom>(BaseList.GetEnumerator()); }

    // ICollection
    public int Count { get { return BaseList.Count; } }
    public bool IsReadOnly { get { return BaseList.IsReadOnly; } }
    public void Add(TTo item) { BaseList.Add((TFrom)(object)item); }
    public void Clear() { BaseList.Clear(); }
    public bool Contains(TTo item) { return BaseList.Contains((TFrom)(object)item); }
    public void CopyTo(TTo[] array, int arrayIndex) { BaseList.CopyTo((TFrom[])(object)array, arrayIndex); }
    public bool Remove(TTo item) { return BaseList.Remove((TFrom)(object)item); }

    // IList
    public TTo this[int index]
    {
        get { return (TTo)(object)BaseList[index]; }
        set { BaseList[index] = (TFrom)(object)value; }
    }

    public int IndexOf(TTo item) { return BaseList.IndexOf((TFrom)(object)item); }
    public void Insert(int index, TTo item) { BaseList.Insert(index, (TFrom)(object)item); }
    public void RemoveAt(int index) { BaseList.RemoveAt(index); }
}

public class CastedEnumerator<TTo, TFrom> : IEnumerator<TTo>
{
    public IEnumerator<TFrom> BaseEnumerator;

    public CastedEnumerator(IEnumerator<TFrom> baseEnumerator)
    {
        BaseEnumerator = baseEnumerator;
    }

    // IDisposable
    public void Dispose() { BaseEnumerator.Dispose(); }

    // IEnumerator
    object IEnumerator.Current { get { return BaseEnumerator.Current; } }
    public bool MoveNext() { return BaseEnumerator.MoveNext(); }
    public void Reset() { BaseEnumerator.Reset(); }

    // IEnumerator<>
    public TTo Current { get { return (TTo)(object)BaseEnumerator.Current; } }
}

Ответ 8

Linq имеет метод ConvertAll. поэтому что-то вроде

list.ConvertAll<Obj>(objBase => objbase.ConvertTo(obj));

Я не уверен, что еще предложить. Я предполагаю, что ObjBase является базовым классом, и если все объекты ObjBase являются объектами Obj, я не уверен, почему у вас будут два объекта в первую очередь. Возможно, я не в курсе.

Изменить: метод list.Cast будет работать лучше, чем указано выше, при условии, что они могут быть защищены друг от друга. Забыл об этом, пока не прочитал другие ответы.

Ответ 9

Это большая боль в С# - вот как были разработаны дженерики. Список не расширяет List, его совсем другой тип. Вы не можете каким-либо образом отбрасывать или назначать их друг другу, единственным вариантом является копирование одного списка в другой.

Ответ 10

Lazarus:
Я думал, что компилятор поймет, что мне нужны действия, выполняемые над объектами списка, а не то, что я пытался создать список.

Дополнительная информация:

public abstract class ObjBase
   {
   }

internal interface IDatabaseObject
   {
   }

public class Obj : ObjBase, IDatabaseObject
   {
   }


internal interface IDatabaseObjectManager
   {
      List<ObjBase> getSomeStuff();
   }

public class ObjManager : IObjManager
{
    public List<Obj> returnStuff()
    {
       return getSomeStuff().Cast <Customer>().ToList<Customer>();
    }

    private List<ObjBase> getSomeStuff()
    {
       return new List<ObjBase>();
    }
}

Теперь код клиента за пределами этой DLL может идти:   ObjManager objM = новый ObjManager();   Список listOB = objM.returnStuff(); Я собираюсь создать несколько типов Obj и ObjManager для этой части (O/RM) приложения.

(В блоке комментариев Darn не хватало символов!: -)

Ответ 11

Вот как я исправил конверсию с

list<SomeOtherObject>

до

object

а затем до

List<object>

fooobar.com/info/132766/...