Почему я не могу привести List <MyObject>к классу, который наследуется от List <MyObject>? - PullRequest
0 голосов
/ 20 апреля 2009

У меня есть объект, который я назову MyObject. Это класс, который контролирует конкретную строку данных.

Затем я получил класс коллекции, который называется MyObjectCollection:

public class MyObjectCollection : List<MyObject> {}

Почему я не могу сделать следующее:

List<MyObject> list = this.DoSomethingHere();
MyObjectCollection collection = (MyObjectCollection)list;

Заранее спасибо.

Редактировать: ошибка InvalidCastException

Ответы [ 5 ]

5 голосов
/ 20 апреля 2009

Поскольку List<MyObject> не является коллекцией MyObjectCollection. Обратное верно: вы можете привести MyObjectCollection к списку, потому что MyObjectCollection наследует от List<MyObject> и, таким образом, для всех намерений и целей IS A List<MyObject>.

Единственное, что вы можете сделать, это определить конструктор в MyObjectCollection, который принимает Ienumerable в качестве параметра и инициализирует себя данными другого, но при этом создается новый объект, содержащий те же данные:

public class MyObjectCollection : List<MyObject> 
{
  public MyObjectCollection(IEnumerable<MyObject> items)
  {
    Addrange(items); 
  }
}

UPDATE: Как отмечено в комментарии, вы МОЖЕТЕ выполнить приведение успешно во время выполнения, при условии, что DoSomething действительно возвращает экземпляр MyObjectCollection. Если это так, то объект фактически является MyObjectCollection, и приведение является полностью законным.

Я бы сказал, это плохая практика, с моей точки зрения, подбрасывать что-то подобное. Если функция возвращает List, вам не следует полагаться на конкретную реализацию List. Либо измените тип возврата DoSomething, если у вас есть эта функция, и верните коллекцию MyObjectCollection, либо обработайте ее в виде списка.

5 голосов
/ 20 апреля 2009

Я предполагаю, что DoSomethingHere не возвращает экземпляр MyObjectCollection.

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

public static object CreateAnObject()
{
    return new object();
}

object o = CreateAnObject();
string s = (string) o;

Это не удастся (во время выполнения), и это совершенно правильно.

Чтобы вернуть его в свой код, если DoSomethingHere на самом деле не вернет MyObjectCollection во время выполнения, приведение не будет выполнено.

2 голосов
/ 20 апреля 2009

Не зная , что именно создается внутри DoSomething (), мы должны принять либо:

У вас неправильное представление о наследовании в .Net.

у вас есть

A : B

B DoSomething() 
{
    return new B();
}
// then this is
B b = new B();
A a = (A)b;

Очевидно, что b - это B, а не A. B может выглядеть очень похоже на A, но это не так (если вы пересекаете происхождение b, вы нигде не найдете A)

Это верно, независимо от используемых Общих принципов (хотя иногда это может привести к ситуациям, когда что-то, что могло бы работать, не видит разницу в контрагенте в c # 4.0)

или

A : B

B DoSomething() 
{
    return new A();
}
// then this is
B b = new A();
A a = (A)b;

Который при отсутствии Generics будет работать.

1 голос
/ 20 апреля 2009

Вы не можете сделать это, потому что (я предполагаю) экземпляр списка, возвращенный из DoSomethingHere , не получен из MyObjectCollection

0 голосов
/ 20 апреля 2009

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

public static implicit operator List<MyObject>(MyObjectCollection oCollection)
{
  //Convert here
  return MyObjectCollection.BaseList;
}

public static implicit operator MyObjectCollection(List<MyObject> oList)
{
  //Convert here
  return new MyObjectCollection(oList);
}
...