40

我是 C# 的新手。我正在阅读 Sealed 关键字。我已经了解了 seal 类。我已经阅读了有关 Sealed 方法的一行,我们也可以在其中制作 Sealed 方法。该行是(通过将方法声明为密封,我们可以避免进一步覆盖此方法。)我创建了一个演示,但不明白上述行和密封方法使用的含义。以下是我的代码: -

using System;

namespace ConsoleApplication2
{
    class Program:MyClass
    {
        public override sealed void Test()
        {
            Console.WriteLine("My class Program");
        }
        static void Main(string[] args)
        {
            Program obj = new Program();
            obj.Test();
            Console.ReadLine();
        }
    }

    class MyClass
    {
        public virtual void Test()
        {
            Console.WriteLine("My class Test");
        }
    }


}

请告诉我为什么我们使用密封方法以及密封方法的优点是什么。

4

7 回答 7

78

好吧,您仅使用两个继承级别进行测试,并且您没有达到“进一步覆盖”方法的地步。如果你把它变成三个,你可以看到什么sealed

class Base {
   public virtual void Test() { ... }
}
class Subclass1 : Base {
   public sealed override void Test() { ... }
}
class Subclass2 : Subclass1 {
   public override void Test() { ... } // Does not compile!
   // If `Subclass1.Test` was not sealed, it would've compiled correctly.
}
于 2010-11-11T07:02:36.717 回答
76

密封是不能成为另一个派生类的基类的类。

未密封类中的密封方法是不能在此类的派生类中重写的方法。

为什么我们使用密封方法?密封方法的优点是什么?

那么,为什么要使用虚拟方法呢?提供一个可以定制类行为的点。那么为什么要使用密封方法呢?提供一个保证您不会在任何派生类的行为中发生与此方法相关的进一步更改的点

可以自定义类行为的点很有用但很危险。它们很有用,因为它们使派生类能够改变基类的行为。它们很危险……等等……因为它们使派生类能够改变基类的行为。虚拟方法基本上允许第三方让你的类做你从未预料或测试过的疯狂的事情。

我喜欢编写符合我预期和测试的代码。密封方法允许您继续允许类的某些部分被覆盖,同时使密封方法具有保证、可测试、稳定的行为,无法进一步定制。

于 2010-11-11T07:10:53.640 回答
22

好吧,如果您不希望任何派生类进一步覆盖您的方法,则只能在方法上使用“密封” 。默认情况下,如果方法未声明为虚拟方法且未覆盖另一个虚拟方法,则方法是密封的。(在 Java 中,默认情况下方法是虚拟的 - 要实现“默认”C# 行为,您必须将方法标记为final。)

就我个人而言,我喜欢谨慎地控制继承——我更喜欢尽可能密封整个类。但是,在某些情况下,您仍然希望允许继承,但要确保某些方法不会被进一步覆盖。一种用途可能是有效地模板方法,例如用于诊断:

public sealed override void Foo(int x)
{
    Log("Foo called with argument: {0}", x);
    FooImpl(x);
    Log("Foo completed");
}

protected abstract void FooImpl(int x);

现在子类不能Foo直接覆盖——它们必须覆盖FooImpl,所以我们的行为总是会在其他代码调用时被执行Foo

当然,模板可能出于其他原因 - 例如强制执行参数验证的某些方面。

以我的经验,密封方法并不经常使用,但我很高兴有这种能力。(我只是希望课程默认是密封的,但这是另一个话题。)

于 2010-11-11T07:02:23.663 回答
2

现在,如果您声明 Program 的子类,您将无法覆盖 Test 方法,这就是重点。

在大多数情况下,您不需要密封方法,但是当您为第三方开发人员必须扩展以创建自己的插件的某些插件系统开发基类时,它们可以证明自己很有用。您可以保留一些服务数据,例如插件名称以及是否启用,并使用密封的方法和属性来执行此操作,这样插件开发人员就不会乱用它。这是密封成员派上用场的一种情况

于 2010-11-11T07:13:11.160 回答
2

密封方法

密封方法用于定义虚拟方法的覆盖级别。

Sealed 关键字始终与 override 关键字一起使用。

密封方法的实际演示

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace sealed_method
{
    class Program
    {
        public class BaseClass
        {

            public virtual void Display()
            {
                Console.WriteLine("Virtual method");
            }
        }

       public class DerivedClass : BaseClass
        {
            // Now the display method have been sealed and can;t be overridden
            public override sealed void Display()
            {
                Console.WriteLine("Sealed method");
            }
        }

       //public class ThirdClass : DerivedClass
       //{

       //    public override void Display()
       //    {
       //        Console.WriteLine("Here we try again to override display method which is not possible and will give error");
       //    }
       //}

        static void Main(string[] args)
        {

            DerivedClass ob1 = new DerivedClass();
            ob1.Display();

            Console.ReadLine();
        }
    }
}
于 2016-10-05T08:36:32.630 回答
0

首先,让我们从一个定义开始;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; }
        ...
    }
}

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

例子

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
}

微软文档

https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/sealed

于 2020-03-02T15:58:13.583 回答
-4

C# 拥有它是因为 Java 具有相同的特性(final方法)。我从未见过合法的用途。

如果您不想允许扩展,则应标记整个类sealed,而不仅仅是一种方法。

于 2010-11-11T07:00:56.083 回答