Почему мы не можем использовать запечатанные классы в качестве универсальных ограничений?

Можно ли предположить то, что причина не состоит в том, чтобы позволить запечатанным классам для ограничений типа в дженериках? У меня только есть одно объяснение, должен дать возможность использовать явные ограничения.

22
задан Grigory Bushuev 4 August 2019 в 03:32
поделиться

4 ответа

Если класс опечатан, то он не может быть наследуемым. Если он не может быть унаследован, он будет единственным типом, действительным для аргумента общего типа [предполагая, что если разрешено быть аргументом типа]. Если это единственный общий аргумент типа, то нет смысла делать его общим! Вы можете просто кодировать против типа в не генерическом классе.

Вот код для этого.

public class A
{
    public A() { }
}

public sealed class B : A
{
    public B() { }
}

public class C<T>
        where T : B
{
    public C() { }
}

Это приведет к ошибке компилятора: 'B' не является действительным ограничением. Использованный тип как ограничение должно быть интерфейсом, незапечатанный класс или тип параметр.

В дополнение к этому, Вы также не можете иметь статический класс как generic type-constraint. Причина проста. Статические классы в компилированной IL помечены как абстрактные и опечатанные, которые не могут быть ни инстанциированы, ни наследованы.

Вот код для этого.

public class D<T>
        where T : X
{
    public D() { }
}

public static class X
{
}

Это приведет к ошибке компилятора:'X': статические классы нельзя использовать как Ограничения.

42
ответ дан 29 November 2019 в 04:12
поделиться

Обнаженное ограничение - это когда один общий тип наследуется от другого, например

where X:Y

Один общий параметр наследуется от другого общего параметра

class Foo<T>
{
    Foo<S> SubsetFoo<S>() where S : T {  }
}

Так что класс не может быть запечатан.

Вы также можете наследовать от дженериков обычным способом, так что вы не захотите, чтобы они были запечатаны.

1
ответ дан 29 November 2019 в 04:12
поделиться

Вы говорите о чем-то подобном:

class NonSealedClass
{
}

class Test<T> where T : NonSealedClass
{
}

Потому что это абсолютно законно.

5
ответ дан 29 November 2019 в 04:12
поделиться

Честно говоря, я не совсем понимаю смысл этого.

Как this.__curious_geek указывает в своем ответе, запечатанный класс не может наследоваться, и поэтому использование его в качестве ограничения может показаться бессмыслицей.

Но нет никакой гарантии, что запечатанный класс никогда не будет "снят" - то есть, что разработчик может изменить его реализацию, чтобы сделать его более удобным для наследования, а затем удалить модификатор sealed из определения класса (или просто удалить ключевое слово sealed без всякой причины).

Я знаю, что многие разработчики на самом деле поощряют такую практику: не удаление ключевого слова sealed как такового, а скорее добавление ключевого слова sealed и поддержка наследования только тогда, когда решение об этом принято явно (и в этот момент, да, удаление ключевого слова sealed).

Поэтому я не уверен, почему вы не можете использовать тип запечатанного класса в качестве общего ограничения. В конце концов, вы всегда можете использовать тип класса, который случайно не имеет производных классов, даже если он не запечатан. Эти два сценария не кажутся мне такими уж разными.

Хотя, возможно, я что-то упускаю. Я уверен, что Eric Lippert мог бы дать довольно убедительное объяснение.

3
ответ дан 29 November 2019 в 04:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: