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


67

我正在浏览一些C#代码以扩展VS2010中的语言支持(好的示例)。我看到一些课internal sealed class

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


11
如果您曾经问​​过“如果它已经在内部,为什么要密封它?”,这将是一个更有趣的问题。
汉斯·帕桑

@Hans Passant也许是要阻止其他开发人员在维护或其他未来开发中扩展它?(当然可以采取删除措施,但如果该类不能在太多继承的情况下正常运行,则应通过密封将其标记为有意义
Kurru

@Hans Passant-为什么不只允许在给定程序集中进行继承?内部类的大量有效使用方案可以扩展为子类。
dexter

Answers:


145

这是一个类:

  • internal:只能从定义的程序集(或好友程序集)中访问。
  • sealed:无法继承。

将类标记为asinternal是防止程序集的外部用户使用它们的一种方法。这实际上是设计封装的一种形式,恕我直言,将不属于预期的公共API \对象模型的类型标记为是一种很好的做法internal。从长远来看,这可以防止您的库用户将自己耦合到您不希望他们使用的类型。这种意外的耦合会损害您更改和发展库实现方式的能力,因为在不破坏客户的情况下就无法更改它们。使用internal有助于使图书馆的公共和可用表面积保持在预期范围内。

将类标记为会sealed阻止这些类被继承。这是一个非常激烈的设计意图,如果一个类已经非常专门化,以至于明智的做法是不应该通过继承直接或通过覆盖其行为来向其添加任何其他功能,则有时这很有用。

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

注意:您可以进一步internal定义范围,因为您可以将一组其他程序集定义为“好友”。这些朋友程序集可以访问您的internal类型。这对于定义协作组件集(例如生产和测试组件)很有用。通常希望测试程序集可以看到它正在测试的程序集中的所有类型。


7
有人会认为密封并不是真正的“大刀阔斧”,应该将其视为默认值……我见过埃里克·利珀特(Eric Lippert)和乔恩·斯凯特(Jon Skeet)谈到了这一点。
Casey

@凯西我完全不同意。我什至认为,在C#中对虚拟的明确需求是巨大的,这是最大的缺点之一(也许是唯一的一大缺点),除非明确禁止,否则默认行为应该是始终允许可扩展性。允许压倒性行为比禁止它更为普遍。
Arijoon

@Arijoon的风险是,某个人重写您的方法可能会完全破坏您的假设。例如,假设虚拟是默认设置,而我覆盖了您的InitializeObject方法。好吧,谁能说它仍然可以正常工作?
Casey

2
@Casey,我完全可以看到你的一面,并从中受益。但是,将其设置InitializeObject为“sealed如果我不想允许继承”是否更好?
阿里洪

1
@Arijoon我不知道;在我看来,这种语言应该比编写可能过于脆弱的代码更容易编写可以按预期运行的代码。
凯西

18
  • internal:只能在同一程序集中访问的类。

    Assembly1.dll:

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

    Assembly2.dll:

    using test;
    ...
    InternalClass c1; // Error
    PublicClass c2; // OK
    
  • 密封的:不能从其派生的类

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

12

内部表示该成员可访问同一程序集中定义的其他类型。Sealed类有点像抽象的对立面。可以实例化它,但不能用作基类。密封一个类的主要原因是防止您的用户摆弄和破坏它。密封类也允许某些编译器优化,这是非密封类无法实现的。


6

internal sealed类是这样的:

internal-仅可从同一装配中访问
sealed-不能被子类化

换句话说,您无法直接使用它。


4

内部表示只能在同一装配中使用,

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

不能继承的密封

密封的类不能继承。将密封类用作基类是错误的。在类声明中使用密封的修饰符可以防止类的继承。


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

密封

首先,让我们从定义开始。密封是一个修饰符,如果将其应用于类使其不可继承,并且如果将其应用于虚拟方法或属性将使其变为非ovveridable

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

由于密封类不能继承,因此不能用作基类,因此抽象类不能使用密封修饰符。同样重要的是要提到结构是隐式密封的

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文档

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.