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

Почему я не могу сделать из списка <MyClass> в List <object>?

У меня есть список объектов, которые относятся к моему типу QuoteHeader, и я хочу передать этот список как список объектов методу, который может принять List<object>.

Моя строка кода читает...

Tools.MyMethod((List<object>)MyListOfQuoteHeaders);

Но во время разработки я получаю следующую ошибку...

Cannot convert type 'System.Collections.Generic.List<MyNameSpace.QuoteHeader>' 
to 'System.Collections.Generic.List<object>'

Мне нужно что-то сделать для своего класса, чтобы это разрешить? Я думал, что все классы наследуют от объекта, поэтому я не могу понять, почему это не сработает?

4b9b3361

Ответ 1

Причина, по которой это не является законной, заключается в том, что она небезопасна. Предположим, что это было законно:

List<Giraffe> giraffes = new List<Giraffe>();
List<Animal> animals = giraffes; // this is not legal; suppose it were.
animals.Add(new Tiger());  // it is always legal to put a tiger in a list of animals

Но "животные" на самом деле являются списком жирафов; вы не можете поставить тигра в список жирафов.

В С# это, к сожалению, законно с массивами ссылочного типа:

Giraffe[] giraffes = new Giraffe[10];
Animal[] animals = giraffes; // legal! But dangerous because...
animals[0] = new Tiger(); // ...this fails at runtime!

В С# 4 это законно для IEnumerable, но не IList:

List<Giraffe> giraffes = new List<Giraffe>();
IEnumerable<Animal> animals = giraffes; // Legal in C# 4
foreach(Animal animal in animals) { } // Every giraffe is an animal, so this is safe

Это безопасно, потому что IEnumerable<T> не предоставляет какой-либо метод, который принимает T.

Чтобы решить вашу проблему, вы можете:

  • Создайте новый список объектов из старого списка.
  • Сделайте метод для получения объекта [], а не List<object>, и используйте небезопасную ковариацию массива.
  • Сделать метод общим, поэтому требуется List<T>
  • Сделать метод принятым IEnumerable
  • Сделайте метод IEnumerable<object> и используйте С# 4.

Ответ 2

Вы не можете отбрасывать List<OneType> до List<OtherType>, поскольку на самом деле это экземпляры списка, который вы хотите отличить, а также самого списка.

существует метод расширения, который позволит вам сделать это (ссылка MSDN):

IEnumerable<Object> myNewEnumerable = myEnumerable.Cast<Object>();

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

Что касается системы, то два типа для ваших списков - это просто разные типы, поэтому это похоже на высказывание:

A objectOfTypeA;
B objectOfTypeB = (B) objectofTypeA;

Чтобы иметь возможность делать актеры, должно быть неявное или явное преобразование между доступными типами, которых нет (если вы не предоставили его, что вы могли бы сделать).

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

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

вам может быть интересно прочитать серию Эрика Липперта по ковариации и контравариантности, поскольку это может быть полезно для вас.

Этот вопрос также может быть полезен

Ответ 3

List<MyClass> x = someList.Select(f => (MyClass)f).ToList();

Ответ 4

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

Tools.MyMethod(MyListOfQuoteHeaders.Cast<OtherType>());

Ответ 5

Спасибо за ответы.

Я объясню, что я хотел сделать, и то, что я нашел в качестве решения.

Мне нужен был метод, который я мог бы вызвать, перейдя в список объектов любого типа, а затем выведет этот список в XML. Также переданному методу будет строка, которая будет представлять собой путь пути к файловой структуре системы, который указывает на местоположение, в которое будет сохранен файл XML. Поскольку у меня постоянно растет количество классов и типов, я хотел бы избежать написания нескольких методов для обслуживания каждого типа класса. Я не уверен, что я даже поступил по этому пути, но это легкое решение моей проблемы и работает. Если с ним возникнут какие-либо проблемы или у кого-то есть комментарии, пожалуйста, не стесняйтесь...

Итак... мой метод теперь выглядит так...

    public static Enums.Status WriteListToXML<T>(string outputPath, List<T> inboundList)
    {
        try
        {
            XmlSerializer xmlSerializer = new XmlSerializer(inboundList.GetType());
            using (StreamWriter streamWriter = System.IO.File.CreateText(outputPath))
            {
                xmlSerializer.Serialize(streamWriter, inboundList);
            }
            return Enums.Status.Success;
        }
        catch (Exception ex)
        {
            return Enums.Status.Failure;
        }
    }

... и моя строка вызова читает...

WriteListToXML<QuoteHeader>(@"C:\XMLDocuments\output\QuoteHeaders.xml", quoteHeadersList);

Как я уже сказал, это может быть не самое верное решение, но оно хорошо работает в моем сценарии.

Ответ 6

Проблема заключается в том, что во время компиляции компилятор испускает 2 отдельных класса: 1, который представляет List<MyClass> и тот, который представляет List<Object>. Они по существу являются двумя отдельными типами. То, как работают общие типы, по крайней мере в .Net.

Предполагая, что это .Net, вы могли бы сделать

MyListOfQuoteHeaders.Cast<Object>()

который в основном выполняет

var objects = new List<Object>();

foreach(var item in MyListOfQuoteHeaders)
{
   objects.Add((object)item);
}

return objects;