C#中的内部密封类是什么?

74

我在查看一些扩展VS2010语言支持的C#代码(Ook示例)时,看到了一些称为internal sealed class的类。

这些类是做什么用的?人们会使用它们吗?


11
如果您问“为什么如果已经是内部的话还要密封”,那这将是一个更有趣的问题。 - Hans Passant
@Hans Passant 也许为了防止其他开发人员在维护或将来的开发中进行扩展?(当然,这很容易移除,但如果该类无法与多重继承很好地配合,那么标记为密封类是有意义的)。 - Kurru
@Hans Passant - 为什么不允许仅在给定程序集内进行继承?有很多有效的使用场景,可以将内部类扩展到子类中。 - dexter
6个回答

156

这是一个类,具有以下特点:

  • internal:只能从定义它的程序集(或友元程序集)中访问。
  • sealed:不能被继承。

将类标记为internal是防止程序集外部用户使用它们的一种方法。这实际上是一种设计封装的形式,我认为标记那些不属于预期公共API/对象模型的类型为internal是一种好的实践。从长远来看,这可以防止你的库用户耦合到你没有打算让他们耦合的类型上。这种意外的耦合会影响你改变和演进库实现方式的能力,因为你不能更改它们而不破坏客户端。使用internal有助于将库的公共和可用表面积限制在预期范围内。

将类标记为sealed防止这些类被继承。这是一种相当激进的设计意图,有时候很有用,如果一个类已经专门化到不应该通过继承直接或通过覆盖其行为添加其他功能。

internalsealed以非常不同的方式修改类型,但它们可以一起使用。

注意:你对internal有进一步的作用域控制,因为你可以将一组其他程序集定义为'友元'。这些友元程序集可以访问你的internal类型。这对于定义一组协同程序集(如生产和测试程序集)非常有用。通常情况下,测试程序集能够看到它正在测试的程序集中的所有类型是有益的。


7
有人认为sealed并不是“极端的”,应该被视为默认选项......我看过Eric Lippert和Jon Skeet讨论过这个问题。 - Casey
1
@Casey 我完全不同意。我甚至认为在C#中显式需要虚拟是迫切的,这是一个很大的缺点(也许是唯一的一个大缺点),默认行为应该始终允许可扩展性,除非明确禁止。允许覆盖行为比禁止它要常见得多。 - Arijoon
@Arijoon 风险在于有人覆盖您的方法可能会完全破坏您的假设。例如,想象一下如果虚拟是默认的,并且我覆盖了您的“InitializeObject”方法。那么,谁能保证它仍然能正常工作呢? - Casey
2
@Casey,我完全理解你的观点和好处。然而,如果我不想允许继承,将InitializeObject设置为sealed不是更好吗? - Arijoon
1
@Arijoon 我不知道;在我看来,编程语言应该使编写能够按预期运行的代码更容易,而不是可能过于脆弱的代码。 - Casey

20
  • internal: 一个只能在同一程序集内访问的类。

    Assembly1.dll:

namespace test {
    internal class InternalClass {
    }

    public class PublicClass { 
    }
} 

Assembly2.dll:

using test;
...
InternalClass c1; // Error
PublicClass c2; // OK
  • sealed: 一个无法被继承的类

  • sealed class SealedClass { ... }
    
    class ChildClass : SealedClass {} //ERROR
    

    13

    Internal 表示该成员可以被同一程序集内定义的其他类型访问。Sealed 类有点像抽象类的相反,它可以被实例化,但不能作为基类使用。将类密封的主要原因是防止用户对其进行更改并破坏其完整性,同时类密封也允许某些编译器优化,而这种优化在非密封类中不可能实现。


    6
    一个 internal sealed 类是指: internal - 只能在同一个程序集内访问
    sealed - 不能被子类继承
    换句话说,你无法直接使用它。

    4

    Internal是指只能在同一个程序集中使用的关键字。

    内部关键字是类型和类型成员的访问修饰符。内部类型或成员仅在同一程序集中的文件中可访问。

    Sealed表示不能被继承。

    封闭类无法被继承。将封闭修饰符用于类声明中,可以防止该类被继承。


    2

    内部

    内部类型或成员只能在同一程序集的文件中访问。

    示例

    // 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 
       }  
    } 
    

    密封的

    首先,让我们从定义开始;“sealed”是一种修改符号,如果应用于类,则使其不可继承,如果应用于虚方法或属性,则使它们无法被覆盖

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

    它的使用示例是专门的类/方法或属性,可能的更改会使它们停止按预期工作(例如,System.Drawing命名空间的Pens类)。

    ...
    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; }
            ...
        }
    }
    

    由于封闭类无法被继承,因此无法用作基类,因此抽象类无法使用sealed修饰符。还需要注意的是,结构体默认是封闭的

    示例

    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
    }
    

    微软文档


    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接