2012-01-17 2 views
8

Рассмотрят следующий класс:класса и общее ограничения типа взаимодействие уровня Метода

public class DerivedClassPool<TBase> where TBase : class 
{ 
    public TBase Get(Type componentType) 
    { 
     // Not important, but you get the idea 
     return Activator.CreateInstance(componentType) as TBase; 
    } 

    public TDerived SomeMethod<TDerived>() where TDerived : TBase 
    { 
     return Get(typeof(TBase)) as TDerived; 
    } 
} 

Обратите внимание, что я ограничил TBase обобщенного класс аргумента будут класс: where TBase : class
Я также ограничил TDerived родовых аргумент метода TBase или что-то вытекающее из этого: where TDerived : TBase.

Я получаю сообщение об ошибке на as TDerived линии:

Параметр типа «TDerived» не может быть использован с «как» оператора, поскольку он не имеет классовый тип ограничения, ни ограничение «класс»

Я понимаю, что для предотвращения ошибок, мне нужно добавить ограничение class, поэтому я хотел бы получить:

where TDerived : class, TBase 

Почему я должен это делать, когда TBase уже ограничен классом, а TDerived ограничен TBase или получен из него?

+1

См. Http://stackoverflow.com/questions/8002148/c-sharp-generics-contraints-propagation. Эрик выставляет его там. –

+1

@ Джейсон, я думаю, что он лучше читал «но». – Joey

+1

@Joey: Достаточно справедливо. Я просто ненавижу, когда предложения начинаются с 'but', хотя использование конъюнктов для начала предложений считается правильным в наши дни. Я обвиняю своего учителя английского языка в средней школе. Он был приверженцем классических английских конвенций. –

ответ

8

ОБНОВЛЕНИЕ: Этот вопрос был the subject of my blog on September 19th, 2011. Спасибо за большой вопрос!


Почему я должен это сделать, когда TBase уже ограничены быть классом и TDerived ограничивается быть TBase или производные от него?

Поскольку тип значения может быть получен из ссылочного типа. int получен из ссылочных типов object и System.ValueType и реализует ряд интерфейсов. Это не делает ссылочный тип int.

Совершенно законно для вас позвонить SomeMethod<int> по экземпляру DerivedClassPool<object>, потому что int является производным от объекта.

Теперь - это случаи, когда ваша критика будет оправдана. Можно построить ситуации, в которых два параметра типа связаны таким образом, что оба они логически могут быть только ссылочными типами, но только один из них классифицируется по языку как «известный как ссылочный тип».

Как упражнение для читателя: можете ли вы его найти? Возможно, потребуется внимательно прочитать раздел 10.1.5 спецификации для точного определения «известного как ссылочный тип».

+0

Возможно ли создать наши собственные типы значений, которые получены из ссылочных типов (в C#)? –

+0

@GeorgeDuckett Почему это актуально? –

+0

@ OskarKjellin: Это не так, мне просто интересно. :) –

2

Потому что TBase может быть интерфейсом, поэтому TDerived может быть типом значения.

+0

TBase должен быть классом? –

+1

Вы в этом уверены? http://msdn.microsoft.com/en-us/library/d5x73970.aspx: 'Аргумент типа должен быть ссылочным типом; это относится также к любому классу, интерфейсу, делегированию или типу массива. ' –

+1

Не знал об этом. Ужасно, что 'class' означает« тип значения »в этом случае –

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