Запечатанный метод в C#

Я новичок в C#. Я читаю о запечатанном ключевом слове. Я узнал о запечатанном классе. Я прочитал строку о запечатанном методе, где мы можем также сделать запечатанный метод. Строка была (Объявляя метод как запечатанный, мы можем избежать дальнейшее переопределение этого метода.) Я создал демо-версию, но не понял, что означает использование вышеуказанной линии и метода запечатывания. Ниже мой код:-

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


}

Скажите, пожалуйста, почему мы используем запечатанные методы и каковы преимущества запечатанных методов.

6 ответов

Решение

Что ж, вы тестируете только с двумя уровнями наследования, и вы не дошли до того, что "переопределяете" метод. Если вы сделаете это три, вы можете увидеть, что 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() { ... }
}

Примером его использования является специализированный класс / метод или свойство, в котором потенциальные изменения могут заставить их перестать работать должным образом (например, класс Pens пространства имен System.Drawing).

...
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 не может быть унаследован, его нельзя использовать в качестве базового класса, и, как следствие, абстрактный класс не может использовать модификатор 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
}

Документация Microsoft

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

У C# есть это, потому что у Java есть идентичная особенность (final методы). Я никогда не видел законного использования.

Если вы не хотите разрешать расширение, весь класс должен быть помечен sealed и не только один метод.

Другие вопросы по тегам