Взаимодействие ограничений общего типа на уровне класса и метода - PullRequest
8 голосов
/ 17 января 2012

Рассмотрим следующий класс:

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 или производнымот этого?

Ответы [ 2 ]

8 голосов
/ 17 января 2012

ОБНОВЛЕНИЕ: Этот вопрос был темой моего блога 19 сентября 2011 года . Спасибо за отличный вопрос!


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

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

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

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

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

2 голосов
/ 17 января 2012

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...