【问题标题】:What is the purpose of "sealed" in C# when "virtual" is optional?当“虚拟”是可选的时,C# 中“密封”的目的是什么?
【发布时间】:2014-04-19 02:51:18
【问题描述】:

如果一个类没有任何虚拟方法,我认为继承一个类不会影响任何没有将实例显式引用为子类实例的代码,即

Subclass obj = new Subclass()

而不是

BaseClass obj = new SubClass()

那么,为什么sealed 会存在呢?

如果您没有将任何内容声明为virtual(我认为在密封类中这样做没有意义),那么它所阻止的只是(例如)ListViewItem 之类的东西,它存储了一些关于它所代表的内容的额外信息对于“知道”该信息存在的代码,与重写方法不同,这对未考虑该子类编写的代码没有影响。

【问题讨论】:

  • 还有更多“显而易见”的答案,但是如果一个类直接在 CLR 之上而不是在 C# 代码中实现并且扩展它会破坏它呢?

标签: c# class oop inheritance sealed


【解决方案1】:

考虑

class A
{
  public virtual void M1();
  public void M2();
}

class B : A
{
  public override sealed void M1();
}

sealed class C : A
{
   //other stuff    
}

class D : A
{
   public new void M2(); //marking A as sealed would prevent this 
}

另请参阅: Do sealed classes really offer performance Benefits? (JITter 可以在知道不能有子类的情况下优化某些调用)

【讨论】:

    【解决方案2】:

    (1) 密封类

    我可能有一个接受BankAccount 类型对象的方法。我不希望您能够创建 EvilBankAccount : BankAccount 并将其传递给我的方法。 EvilBankAccount 可能会破坏我的系统,该系统对BankAccount 做出假设——例如,它可以被序列化。也许我克隆 BankAccount 以防止在提交后进行外部操作,而 EvilBankAccount 克隆就好了,但在其构造函数中启动了一个计时器,每 30 秒自动增加余额。

    (2) 密封件

    您可以覆盖虚拟方法或属性,但将其密封,使其无法在继承层次结构中进一步覆盖。这里的一个用例是当您需要从构造函数访问成员时。

    【讨论】:

    • 如果我真的想调用你的方法,我不确定我是否接受这个“EvilBankAccount”位 - 我不能只使用反射吗?
    • 如果您愿意,可以使用反射调用该方法,但如果我已将其密封,您仍然无法创建和传递源自BankAccount 的任何内容。
    • 我同意这与其说是信任或安全问题,不如说是防止滥用可能导致其无法运行的 API 的一种方法。然而,这不是答案的本质。
    • 但是如果BankAccount参数没有明确声明为EvilBankAccount,方法隐藏会有什么影响呢?如果方法接受一个已经构造的对象而不是调用new本身,构造函数参数与它有什么关系?
    • 密封BankAccount 也会限制为自动测试创建派生类型的任何可能性。所描述的场景更多关于代码安全,为什么您的安全代码会创建EvilBankAccount 的实例?
    【解决方案3】:

    我个人并没有从密封类中获得太多好处,并且同意,在处理 UI 类并希望通过继承添加一些自定义行为时可能会令人沮丧。 但是,我在这里找到了一个提供一些想法的答案。

    Why seal a class?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-20
      • 1970-01-01
      • 1970-01-01
      • 2016-02-23
      • 2019-09-24
      • 2022-09-25
      相关资源
      最近更新 更多