Что такое внутренний запечатанный класс в С#?

Я просматривал некоторый код С# для расширения языковой поддержки в VS2010 (пример Ook). Я видел несколько классов под названием internal sealed class

Что они делают? Будет ли кто-нибудь использовать их?


person Byron Whitlock    schedule 06.01.2011    source источник
comment
Это был бы более интересный вопрос, если бы вы спросили, зачем запечатывать его, если он уже внутренний?   -  person Hans Passant    schedule 06.01.2011
comment
@Hans Passant Может быть, чтобы другие разработчики не расширяли его при обслуживании или других будущих разработках? (Легко удалить, конечно, но если класс не будет хорошо работать с большим количеством наследования, имеет смысл пометить его как таковой, запечатав его.   -  person Kurru    schedule 07.01.2011
comment
@Hans Passant - почему бы не разрешить наследование только в данной сборке? Множество допустимых сценариев использования для внутреннего класса, которые можно расширить до подклассов.   -  person dexter    schedule 07.01.2011


Ответы (6)


Это класс, который:

  • internal: доступ возможен только из сборки, в которой он определен (или из дружественных сборок).
  • sealed: Не может быть унаследовано.

Пометка классов как internal — это способ предотвратить их использование внешними пользователями сборки. Это действительно форма инкапсуляции дизайна, и IMHO рекомендуется помечать типы, которые не являются частью предполагаемых общедоступных моделей API\объектов, как internal. В долгосрочной перспективе это предотвратит привязку пользователей вашей библиотеки к типам, которые вы им не предназначали. Такого рода непреднамеренная связь вредит вашей способности изменять и развивать способ реализации ваших библиотек, поскольку вы не можете изменить их, не нарушив работу своих клиентов. Использование internal помогает сократить общедоступную и полезную площадь библиотеки до запланированного уровня.

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

internal и sealed изменяют типы совершенно по-разному, но их можно использовать вместе.

Примечание. У вас есть дополнительные возможности управления областью действия internal, поскольку вы можете определить набор других сборок как "друзей". Эти дружественные сборки могут получить доступ к вашим internal типам. Это может быть полезно для определения наборов взаимодействующих сборок, таких как производственные и тестовые сборки. Часто желательно, чтобы тестовая сборка могла видеть все типы в тестируемой сборке.

person Tim Lloyd    schedule 06.01.2011
comment
Кто-то может возразить, что запечатывание не является чем-то радикальным и его следует рассматривать по умолчанию... Я видел, как об этом говорили Эрик Липперт и Джон Скит. - person Casey; 04.04.2014
comment
@ Кейси, я совершенно не согласен. Я даже считаю, что явная потребность в виртуальном языке является резкой в ​​С# и является одним из больших недостатков (возможно, единственным большим), и поведение по умолчанию должно всегда разрешать расширяемость, если это явно не запрещено. Гораздо чаще разрешается подавляющее поведение, чем запрещается. - person Arijoon; 30.04.2016
comment
@Arijoon Риск заключается в том, что кто-то, отменяющий ваш метод, может полностью разрушить ваши предположения. Например, представьте, если бы виртуальный был по умолчанию, и я отменил бы ваш метод InitializeObject. Ну, кто сказал, что это все еще будет работать, верно? - person Casey; 01.05.2016
comment
@Casey, я полностью вижу твою сторону и пользу от этого. Тем не менее, не лучше ли установить InitializeObject как sealed, если я не хочу разрешать наследование? - person Arijoon; 01.05.2016
comment
@Arijoon Я не знаю; по моему мнению, язык должен упростить написание кода, который будет функционировать должным образом, чем код, который может быть слишком хрупким. - person Casey; 02.05.2016

  • внутренний: класс, к которому можно получить доступ только внутри той же сборки.

    Сборка1.dll:

    namespace test {
        internal class InternalClass {
        }
    
        public class PublicClass { 
        }
    } 
    

    Сборка2.dll:

    using test;
    ...
    InternalClass c1; // Error
    PublicClass c2; // OK
    
  • запечатанный: класс, который не может быть производным от

    sealed class SealedClass { ... }
    
    class ChildClass : SealedClass {} //ERROR
    
person HyLian    schedule 06.01.2011

Внутренний означает, что элемент доступен для других типов, определенных в той же сборке. Класс Sealed является своего рода противоположностью абстрактного. Он может быть создан, но не может служить базовым классом. Основная причина, по которой нужно запечатать класс, состоит в том, чтобы ваши пользователи не возились с ним и не сломали его. Также бывает так, что запечатывание класса допускает определенные оптимизации компилятора, которые невозможны с незапечатанными классами.

person HABJAN    schedule 06.01.2011

Класс internal sealed — это:

internal — Доступно только из той же сборки
sealed — Не может быть подклассом

Другими словами, вы не можете использовать его напрямую.

person Powerlord    schedule 06.01.2011

Внутренний означает, что его можно использовать только в той же сборке,

Ключевое слово internal — это модификатор доступа к типам и членам типов. Внутренние типы или элементы доступны только в файлах в той же сборке.

запечатаны, которые нельзя наследовать

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

person Arsen Mkrtchyan    schedule 06.01.2011

ВНУТРЕННЯЯ

Внутренние типы или члены доступны только в файлах той же сборки.

Пример

// Assembly1.cs  
// Compile with: /target:library  
internal class BaseClass   
{  
   public static int intM = 0;  
} 
// Assembly1_a.cs  
// Compile with: /reference:Assembly1.dll  
class TestAccess   
{  
   static void Main()   
   {  
      var myBase = new BaseClass();   // compile error 
   }  
} 

ЗАПЕЧАТАННО

Прежде всего, давайте начнем с определения; запечатанный — это модификатор, который при применении к классу делает его ненаследуемым, а при применении к виртуальным методам или свойствам делает их неподдающимися проверке.

public sealed class A { ... }
public class B 
{
    ...
    public sealed string Property { get; set; }
    public sealed void Method() { ... }
}

Примером его использования является специализированный класс/метод или свойство, в котором возможные изменения могут привести к тому, что они перестанут работать должным образом (например, класс Pens пространства имен System.Drawing).

...
namespace System.Drawing
{
    //
    // Summary:
    //     Pens for all the standard colors. This class cannot be inherited.
    public sealed class Pens
    {
        public static Pen Transparent { get; }
        public static Pen Orchid { get; }
        public static Pen OrangeRed { get; }
        ...
    }
}

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

Пример

public class BaseClass {
    public virtual string ShowMessage()
    {
        return "Hello world";
    }
    public virtual int MathematicalOperation(int x, int y)
    {
        return x + y;
    }
}
public class DerivedClass : BaseClass {
    public override int MathematicalOperation(int x, int y) 
    {
        // since BaseClass has a method marked as virtual, DerivedClass can override it's behavior
        return x - y;
    }
    public override sealed string ShowMessage()
    {
        // since BaseClass has a method marked as virtual, DerivedClass can override it's behavior but because it's sealed prevent classes that derive from it to override the method
        return "Hello world sealed";
    }
}
public class DerivedDerivedClass : DerivedClass
{
    public override int MathematicalOperation(int x, int y)
    {
        // since BaseClass has a method marked as virtual, DerivedClass can override it's behavior
        return x * y;
    }
    public override  string ShowMessage() { ... } // compile error
}
public sealed class SealedClass: BaseClass {
    public override int MathematicalOperation(int x, int y)
    {
        // since BaseClass has a method marked as virtual, DerivedClass can override it's behavior
        return x * y;
    }
    public override string ShowMessage()
    {
        // since BaseClass has a method marked as virtual, DerivedClass can override it's behavior but because it's sealed prevent classes that derive from it to override the method
        return "Hello world";
    }
}
public class DerivedSealedClass : SealedClass
{
    // compile error
}

Документация Microsoft

person Ivan Porta    schedule 02.03.2020