2015-07-30 2 views
3

В основном я получил эти примеры классов:Cast неизвестного объекта общего интерфейс интерфейса (от первоначально явного общего типа универсального типа коллекции типа)

public interface IHasParts<TCollectionType> : where TCollectionType : ICollection 
{ 
    TCollectionType Parts { get; set; } 
} 

public class CarPart 
{ 
    //... 
} 

public class Car : IHasParts<List<CarPart>> 
{ 
    public List<CarPart> Parts { get; set; } 
    //... 
} 

Да, мне нужно использовать общий интерфейс ICollection здесь , потому что для классов, реализующих IHasParts, нужны разные типы списков Parts, основанные на некоторых жестких запрограммированных условиях.

Теперь я получаю неизвестный объект т.е. Car и мне нужно, чтобы бросить его до самого высокого родителя, который все еще имеет свойство Parts в наличии:

Car c = new Car() { 
    Parts = new List<CarPart>() { 
    // ... 
    } 
}; 

object o = (object)c; 

int partsCount = ((IHasParts<ICollection>)o).Parts.Count; // InvalidCastException 

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

ответ

2

Если вы определяете класс автомобилей с ICollection вместо List<CarPart>, затем работает:

public class Car : IHasParts<ICollection> 
{ 
    public ICollection Parts { get; set; } 
} 

Вы все еще можете инициализировать части с List<CarPart>

+1

Затем я могу полностью удалить общий тип 'IHasParts' и определить' Parts' сильного типа интерфейса 'ICollection'. Конечно, это может быть решение, все должно использовать 'ICollection'. Некоторые классы, которые реализуют «IHasParts», просто используют разные типы инициализированных списков, такие как «ObservableCollection <>». Если я инициализирую 'Parts' типа' ICollection' с объектом 'ObservableCollection', то подстрочные события этой коллекции все равно должны срабатывать, не так ли? – modiX

+1

@modiX, да, они будут. И я лично думаю, что устранение дженериков все вместе было бы лучшим решением в вашем случае. –

4

Это проблема с отклонениями.

Вы предполагаете, что, поскольку List<T> является подтипом ICollection, то IHasParts<List<T>> должен тоже быть подтипом IHasParts<ICollection>. Это не так.

Если вы хотите IHasParts<A> быть подтипом IHasParts<B> где A является подтипом B, то вам нужно сделать IHasPartsковариантны в параметре типа T (с помощью ключевого слова out).

public interface IHasParts<out TCollectionType> : where TCollectionType : ICollection 
{ 
    TCollectionType Parts { get; } 
} 

Для типа быть ковариантен, T может быть использован только в ковариант- позиции: метод типов возврата, получить только типы недвижимости и получить только для шаговых.

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

+1

Вы не можете использовать «из» и свойств частей с сеттер – Backs

+0

@Backs Забыли для удаления сеттера (хотя я упоминал, что он не может использоваться в настраиваемых свойствах), спасибо! – dcastro

+0

добро пожаловать! – Backs

1

Добавить абстрактный класс заботиться о указав ICollection тип. Объявите ваш код что-то вроде этого:

public interface IHasParts 
{ 
    ICollection Parts { get; } 
} 

public abstract class HasParts<TCollectionType, TPartType> : IHasParts where TCollectionType : ICollection 
{ 

    public TCollectionType Parts; 


    ICollection IHasParts.Parts { get { return this.Parts; } } 

} 

public class CarPart 
{ 
    //... 
} 

public class Car : HasParts<List<CarPart>, CarPart> 
{ 
    protected void AddParts() 
    { 
     this.Parts.Add(new CarPart()); 
    } 
} 

UPDATE:

Вот обновленная версия вашего DotNetFiddle: https://dotnetfiddle.net/O3JZgc

Смежные вопросы