繁体   English   中英

C#中的密封方法

[英]Sealed method in C#

我是 C# 新手。我正在阅读有关 Sealed 关键字的信息。我了解了 Sealed 类。我已经阅读了有关 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");
        }
    }


}

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

好吧,您仅使用两个继承级别进行测试,并且您还没有达到“进一步覆盖”方法的地步。 如果你把它变成三个,你可以看到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.
}

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

在未密封类的密封方法是不能在派生类这个类的被覆盖的方法。

为什么我们使用密封方法? 密封方法有哪些优点?

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

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

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

好吧,如果您不希望任何派生类进一步覆盖您的方法,则只能在方法上使用“密封”。 如果方法未声明为虚拟方法且未覆盖另一个虚拟方法,则默认情况下它们是密封的。 (在 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时执行。

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

根据我的经验,密封方法并不经常使用,但我很高兴有这种能力。 (我只是希望类在默认情况下是密封的,但这是另一个对话。)

密封方法

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

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();
        }
    }
}

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

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM