С # неявное преобразование из базового класса

У меня есть такой класс коллекции:

public class SomeDataCollection : List<ISomeData>
{
    // some method ...
}

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

SomeDataCollection someDatas = new List<ISomeData>();

Невозможно неявно преобразовать тип List<ISomeData> в SomeDataCollection. Существует явное преобразование (вам не хватает приведения?)

поэтому я пытаюсь создать неявное покрытие внутри класса коллекции SomeDataCollection:

public static implicit operator SomeDataCollection(List<ISomeData> l)
{
    var someDatas = new SomeDataCollection();
    someDatas.AddRange(l);
    return someDatas;
}

но он сказал, что я не могу создать такой конвертер:

SomeDataCollection.implicit operator SomeDataCollection(List<ISomeData>): определяемые пользователем преобразования в базовый класс или из него запрещены

И когда я бросил это так:

SomeDataCollection someDatas = (SomeDataCollection)new List<ISomeData>();

он выдает ошибку, в которой говорится:

System.InvalidCastException: невозможно преобразовать объект типа List<ISomeData> в тип SomeDataCollection.

Как я могу это сделать:

SomeDataCollection someDatas = new List<ISomeData>();

без ошибки? Пожалуйста помоги. Заранее спасибо.


person John Isaiah Carmona    schedule 27.06.2012    source источник
comment
возможное дублирование: stackoverflow.com/ questions / 3401084 /   -  person albertjan    schedule 27.06.2012


Ответы (4)


new List<ISomeData>(); по-прежнему остается просто List<ISomeData>. Это не SomeDataCollection. Суть создания подкласса заключается в том, что подкласс может иметь дополнительное состояние и т. Д., Но объект (однажды созданный) никогда не меняет тип.

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

Вы можете просто использовать:

var data = new SomeDataCollection();

Однако я должен добавить, что, откровенно говоря, подкласс List<T> редко бывает полезным. Не в последнюю очередь, он не предоставляет никаких полезных virtual методов, поэтому вы не можете настроить поведение. Честно говоря, я бы просто использовал List<ISomeData> (и полностью удалил SomeDataCollection), если у меня нет ясной и очевидной цели для этого. А затем: я мог бы инкапсулировать список или унаследовать от Collection<T>.

Вы всегда можете просто добавить метод как метод расширения?

public static class Utils {
    public static void SomeMethod(this IList<ISomeData> list) {
      ...
    }
}

тогда:

var list = new List<ISomeData>();
...
list.SomeMethod();
person Marc Gravell    schedule 27.06.2012
comment
На самом деле я не просто помещаю только что созданный экземпляр List<ISomeData> в SomeDataCollection, это был всего лишь образец: P. Я используюList<T>, потому что в нем уже есть функция для добавления, удаления и т. Д. Объектов, и у меня есть некоторые дополнительные методы и свойства в моем классе SomeDataCollection, который специфичен только для типа List<ISomeData>. - person John Isaiah Carmona; 27.06.2012
comment
@John IMO, что что-то и есть список и, имеет собственное состояние, является ошибкой; многие фреймворки / библиотеки ненавидят это - связывание, сериализацию, материализацию и т. д. ИМО, у вас должен быть объект, который имеет эти свойства, и который также имеет IList<Foo> Items {get;} - person Marc Gravell; 27.06.2012
comment
Часто бывает полезно создать подкласс List ‹T›. Хорошим примером может служить список, который можно адаптировать к различным условиям и в который для этой цели добавлены свойства и методы. Однако даже в этих случаях T обычно остается T. - person Thomas Phaneuf; 30.08.2020
comment
@ThomasPhaneuf, поскольку List<T> не предоставляет никаких полиморфных API-интерфейсов, неясно, что он может сделать с пользой для адаптации к чему-либо. - person Marc Gravell; 01.09.2020

Прежде всего, почему вы хотите записать new List<ISomeData> в переменную, определенную как SomeDataCollection? Возможно, вы действительно хотели SomeDataCollection someDatas = new SomeDataCollection();

Что касается сообщений об ошибках, первое сообщение об ошибке сообщает вам, что List<ISomeData> не является производным от SomeDataCollection, поэтому вы не можете делать с ним то, что делали бы с SomeDataCollection, поэтому вы не можете записать его в переменную, которая определена как SomeDataCollection ( представьте, например, если бы в SomeDataCollection было public void someMethod(), а позже в коде вы бы назвали someDatas.someMethod()).

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

SomeDataCollection a = new SomeDataCollection();
List<ISomeData> b = (List<ISomeData>)a;
SomeDataCollection c = (SomeDataCollection)b;

Он должен вызывать ваш конвертер или нет?

В основном код, который вы пытаетесь написать, очень неправильный для начала, поэтому нам нужно знать, что вы пытаетесь сделать, и тогда, возможно, мы сможем сказать вам решение вашей корневой проблемы (а не проблемы «как сделать компиляцию этого кода»).

person penartur    schedule 27.06.2012

Не лучше ли реализовать конструктор в SomeDataCollection?

public SomeDataCollection() : base() { }

Конечно, это можно было бы дополнить

public SomeDataCollection(IEnumerable<ISomeData> collection) 
    : base(collection) { }

Тогда вы сможете инициализировать свой SomeDataCollection следующим образом:

SomeDataCollection someData = new SomeDataCollection();
SomeDataCollection someOtherData = 
    new SomeDataCollection(collectionOfSomeData);

и по-прежнему иметь доступ ко всем общедоступным методам и свойствам в List<ISomeData>.

person Anders Gustafsson    schedule 27.06.2012

Это не проблема с дженериками. В C # вам не разрешено явно преобразовывать базовый класс в производный класс.

person Eugene    schedule 27.06.2012