"Тени" и "Переопределения" в VB.NET

Какое значение имеют два ключевых слова Тени и Отменяет? Что они делают и для какого контекста предпочтительнее тот или иной?

Вы можете подумать о том, чтобы принять ответ @Nика, так как он намного полезнее. (Кроме того, довольно странно иметь серый ответ наверху ...)

Cullub 31.07.2017 19:28

Я так не думаю. Принятый ответ объясняет, что они делают и почему слежка не совсем предпочтительна.

bcpermafrost 14.08.2017 15:49

документация говорит: «Основная цель затенения (которое также известно как сокрытие по имени) - сохранить определение членов вашего класса. Базовый класс может претерпеть изменение, которое создает элемент с тем же именем, что и у вас уже есть. Если это произойдет, модификатор Shadows принудительно разрешает ссылки через ваш класс на член, который вы определили, а не на новый элемент базового класса ".

Ama 02.04.2021 19:42
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
65
3
67 551
17
Перейти к ответу Данный вопрос помечен как решенный

Ответы 17

Ответ принят как подходящий

Я бы не стал считать Shadows действительно концепцией ООП. Переопределения означает, что вы предоставляете новые или дополнительные функции для метода / свойства и т. д., Которые были объявлены в классе-предке. Тени действительно обманывают компилятор, заставляя его думать, что родительский метод / свойство и т. д. Даже не существует.

Мне не нужны тени. Придерживайтесь переопределений. Эти полезные маленькие «функции», которые VB предоставлял годами, всегда в конечном итоге в какой-то момент вызывают у вас горе.

-1. Тени - отличное и полезное понятие. Он скрывает все методы базового класса с тем же именем и заставляет использовать объявленный метод. Переопределения не скрывают все методы базового класса.

user50612 21.01.2009 01:44

Как только вы затеняет унаследованный метод, класс больше не может считаться истинным потомком его предка. ИМХО, это не совсем ООП, и я сомневаюсь в дизайне приложения, которое могло бы привести к этому пути. В некоторых случаях это может быть необходимо, но обычно нет.

Jim Petkus 21.01.2009 04:51

Я согласен, однако, вопрос заключается в том, что они делают и в каком контексте они используются, а не в том, считает ли кто-нибудь их концепциями ООП.

user50612 25.01.2009 01:58

-1 Эквивалент C# - «новый», поэтому частная новая строка Test () {...} делает то же самое. Не просто "проблема" vb.net

Pondidum 24.09.2009 18:54

Вы заслуживаете -2, сначала за неуважение к очень полезному слову Shadows, а затем за незнание основных ключевых слов языка, которым вы так гордитесь, "оскорбление" других языков.

Shimmy Weitzhandler 17.11.2009 01:22

-1; как утверждали другие, это на самом деле не отвечает на вопрос.

Rob 10.05.2010 20:58

-1 за то, что сказать «Тени» - плохая черта только потому, что вы не понимаете ее значения.

Dima 04.07.2012 11:33

Я не уверен, стоит ли голосовать против этого ответа, потому что все исправления от других отрицателей настолько полезны, что я бы не хотел, чтобы отвечающий отмечал ответ удаленным.

pseudocoder 08.11.2012 18:58

Я согласен. Люди стали настолько агрессивными в голосовании против людей, что говорят все, что им не нравится. Разногласия - полезные люди!

Jeff 14.08.2020 00:06

Я согласен с Джимом. Я также никогда не находил законного применения Shadows. Обычно, если я это вижу, я предполагаю, что этот подраздел кода нужно немного реорганизовать.

Я полагаю, что это так, чтобы вы могли скрыть метод из сборки, в которой у вас нет контроля над исходным кодом. В этом случае рефакторинг родительского класса будет невозможен.

-1. Если тени используются правильно, в рефакторинге нет необходимости.

user50612 21.01.2009 01:47

Я бы поставил под сомнение объектно-ориентированный дизайн, который во многом полагается на использование методов затенения. Если производный класс действительно является более конкретным типом базового класса, он обычно должен только расширять функциональные возможности, а не удалять функциональные возможности.

Chad Braun-Duin 21.01.2009 07:19

Переопределения - расширение или создание альтернативных функций для метода.

Пример: добавить или расширить функциональность события Paint окна.


    Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
        MyBase.OnPaint(e) ' retain the base class functionality
        'add code for extended functionality here
    End Sub

Shadows - переопределяет унаследованный метод и заставляет его использовать все классы, экземпляры которых имеют этот тип. Другими словами, метод не перегружен, а переопределяется, а методы базового класса недоступны, что вынуждает использовать функцию, объявленную в классе. Shadows сохраняет или сохраняет определение метода, так что оно не уничтожается при изменении методов базового класса.

Пример: Заставить все классы «B» использовать это странное определение Add, чтобы, если методы Add класса A были изменены, это не повлияло на добавление B. (Скрывает все методы «Добавить» базового класса. Невозможно вызвать A.Add (x, y, z) из экземпляра B.)


    Public Class A
        Public Function Add(ByVal x As Integer, ByVal y As Integer) As Integer
            Return x + y
        End Function
        Public Function Add(ByVal x As Integer, ByVal y As Integer, ByVal z As Integer) As Integer
            Return x + y + z
        End Function
    End Class
    Public Class B
        Inherits A
        Public Shadows Function Add(ByVal x As Integer, ByVal y As Integer) As Integer
            Return x - y
        End Function
    End Class

Это противоречит нескольким принципам объектно-ориентированного программирования, поэтому я хотел бы привести пример практического использования (приведенное выше - нет). Вот что я имею в виду под «новичком»: это, по сути, ненужный механизм, который создает плохой, неподключаемый интерфейс. Полная противоположность хорошему объектно-ориентированному дизайну.

Konrad Rudolph 21.01.2009 01:54

В частности, ваш код не будет работать с полиморфными экземплярами A: Dim x As A = new B() : x.Add(1, 2).

Konrad Rudolph 21.01.2009 01:57

Я согласен с Джимом, Чадом и Конрадом. Тени против ОО.

chyne 21.01.2009 18:52

К счастью для вас, эта ветка посвящена тому, что они делают и в каком контексте используются.

user50612 22.01.2009 01:45

Отменяет - более нормальный квалификатор. Если дочерний класс переопределяет функцию базового класса таким образом, то независимо от того, как ссылается дочерний объект (с использованием ссылки на базовый класс или дочерний класс), вызывается дочерняя функция.

С другой стороны, если функция дочернего класса Тени является функцией базового класса, тогда дочерний объект, доступ к которому осуществляется через ссылку базового класса, будет использовать эту функцию базового класса, несмотря на то, что он является дочерним объектом. Определение дочерней функции используется только в том случае, если доступ к дочернему объекту осуществляется с использованием соответствующей дочерней ссылки.

Человек, задавший вопрос, кажется порядочным пользователем SO, так почему этот ответ не является принятым ответом?

Rudey 08.11.2012 13:21

Это технически правильный ответ, но следует отметить опасности использования Shadows (vb.net) / new (C#), как в этой ориентированной на C# статье msdn.microsoft.com/en-us/library/ms173153%28v=vs.80%29.aspx и в этом прекрасном SO-QA stackoverflow.com/questions/13162542/…

pseudocoder 08.11.2012 19:07

Но если один из Shadows является участником с одним и тем же участником, мы круты, верно? Вы спросите, зачем это нужно? При наследовании и реализации одного и того же события ... По крайней мере, я вижу единственный способ решить эту проблему: stackoverflow.com/questions/14825021/…

d7samurai 12.02.2013 09:20

Пример затенения: предположим, что вы хотите использовать функцию в стороннем компоненте, но функция защищена. Вы можете обойти это ограничение с помощью простого наследования и предоставления теневой функции, которая в основном вызывает свою базовую функцию:

Public Class Base

    Protected Sub Configure()
        ....
    End Sub

End Class

Public Class Inherited
    Inherits Base

    Public Shadows Sub Configure()
        MyBase.Configure()
    End Sub

End Class

Это недавняя ссылка MSDN: Различия между затенением и переопределением

Затенение защищает от последующей модификации базового класса, которая вводит член, который вы уже определили в своем производном классе. Обычно затенение используется в следующих случаях:

** Вы ожидаете, что ваш базовый класс может быть изменен для определения элемента с тем же именем, что и ваше. *

** Вам нужна свобода изменения типа элемента или последовательности вызова. *

(Мне еще предстоит исследовать использование в отношении объема и типов)

Я хотел использовать System.Web.HttpContext.Current.Response вместо Response.redirect и нуждался в удобстве кодирования как Response.redirect. Я определил свойство только для чтения с именем Response, чтобы затенять оригинал в базовом классе. Я не мог использовать переопределения, так как это свойство нельзя переопределить. Очень удобно:)

Скорее всего, затенение не делает того, что вы думаете.

Рассмотрим следующие классы:

Public MustInherit Class A 
    Public Function fX() As Integer
        Return 0
    End Function
End Class

Public Class B
    Inherits A 
    Public Shadows Function fX() As Integer
        Return 1
    End Function 
End Class

Сейчас пользуюсь ими:

Dim oA As A
Dim oB As New B
oA = oB

Вы, наверное, думаете, что oA и oB - это одно и то же, верно?

Неа.

oA.fx = 0, а oB.fx = 1

Имхо, это очень опасное поведение, о котором почти не упоминается в документации.

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

Таким образом, хотя есть законное использование теней, скорее всего, все, что вы делаете, не относится к их числу, и этого следует избегать.

Хорошая иллюстрация того, где вы можете столкнуться с проблемами при использовании этой функции. Обратите внимание, что этот эффект также возникает, если вы перебираете коллекцию базового класса с экземплярами унаследованного класса в коллекции.

pseudocoder 08.11.2012 19:09

Ключевое слово «shadows» по существу говорит: «Если тот, кто обращается к этому объекту, знает, что он принадлежит к этому типу или к одному из его потомков, используйте этот член; в противном случае используйте базовый». Простейшим примером этого может быть базовый класс ThingFactory, который включает метод MakeNew, который возвращает Thing, и класс CarFactory, производный от ThingFactory, чей метод MakeNew всегда возвращает Thing, который будет иметь производный тип Car. Если подпрограмме известно, что ThingFactory, который она содержит, является, в частности, CarFactory, то она будет использовать теневой CarFactory.MakeNew (если он существует), который может указывать возвращаемый тип как Car. Если подпрограмма не знает, что ее ThingFactory на самом деле является CarFactory, она будет использовать не затененный MakeNew (который должен вызывать внутренний защищенный переопределяемый метод MakeDerivedThing).

Между прочим, еще одно хорошее использование теней - предотвратить доступ производных классов к защищенным методам, которые больше не будут работать. Невозможно просто скрыть член от производных классов, кроме назначения нового, но можно запретить производным классам делать что-либо с защищенным членом, объявив новый защищенный пустой класс с этим именем. Например, если вызов MemberwiseClone для объекта приведет к его поломке, можно объявить:

  Protected Shadows Class MemberwiseClone
  End Class
Note that this does not violate OOP principles like the Liskov Substitution Principle, since that only applies in cases where a derived class might be used in place of a base-class object. If Foo and Bar inherits from Boz, a method which accepts a Boz parameter may legitimately be passed in a Foo or Bar instead. On the other hand, an object of type Foo will know that its base-class object is of type Boz. It will never be anything else (e.g. it's guaranteed not to be a Bar).

Я думаю, что здесь действительно есть два сценария, и оба они законны. Вы действительно могли бы разбить их на конструктора базового класса и разработчика спустя годы, который реализует подкласс, который не может изменять базовый класс. Так что да, если у вас есть такая роскошь, лучше всего отказаться от этого. Это чистый подход OOD.

С другой стороны, у вас может быть что-то вроде приведенного выше примера, когда вы находитесь на другом конце этого уравнения, и вам нужно реализовать подкласс, и вы не можете изменить тот факт, что метод, который вам нужно переопределить, не помечен как переопределяемый. Возьмем к примеру

Public Shadows Function Focus() As Boolean
    txtSearch.Focus()
    Return MyBase.Focus()
End Function

В этом случае я наследую свой класс от класса управления Winform, который, к сожалению, не помечен как переопределяемый. На данный момент мне нужно просто сделать код «чистым» или сделать его более понятным. Клиент этого элемента управления просто хочет вызвать control.Focus () и, вероятно, не заботится об этом. Я мог бы назвать этот метод FocusSearchText () или Focus2 и т. д., Но я считаю, что приведенное выше намного проще для клиентского кода. Это правда, что если клиент затем выберет этот элемент управления как базовый класс и вызовет Focus, мой код не запустится. Но это довольно отдаленно.

В конце концов, дело сводится к вынесению приговора, и вам придется его сделать.

Shadow позволяет вам делать определенные вещи, которые нельзя сделать с помощью переопределений.

В моем случае: у меня есть несколько классов таблиц с универсальными функциями; но для кого сами коллекции бывают разных типов.

Public Class GenericTable
Protected Friend Overridable Property Contents As System.Collections.Generic.List(Of GenericItem)
    ... do stuff ...
End Class

Тогда у меня есть конкретные isntances:

Public Class WidgetTable
Inherits GenericTable
Protected Friend Shadows Property Contents As System.Collections.Generic.List(Of Widget)
    ... stuff is inhereted ...
End Class

Я не смог переопределить, потому что тип изменен.

Потому что вам нужен перегрузка только для типа результата. Итак, вам нужно использовать методы тень всеMyBase.Contents, чтобы «избавиться» от перегрузки, которую вы не можете использовать.

Mark Hurd 05.10.2012 04:37

Иногда небольшой пример действительно помогает понять разницу с технической точки зрения.

Sub Main()

    Dim o As New ChildClass

    Console.WriteLine(o.GetValOverride()) ' Prints 2
    Console.WriteLine(o.GetValShadow()) ' Prints 2
    Console.WriteLine(CType(o, ParentClass).GetValOverride()) ' Prints 2
    Console.WriteLine(CType(o, ParentClass).GetValShadow()) ' Prints 1
    Console.ReadLine()

End Sub

Class ParentClass

    Public Overridable Function GetValOverride() As String
        Return "1"
    End Function

    Public Function GetValShadow() As String
        Return "1"
    End Function

End Class

Class ChildClass
    Inherits ParentClass

    Public Overrides Function GetValOverride() As String
        Return "2"
    End Function

    Public Shadows Function GetValShadow() As String
        Return "2"
    End Function

End Class

Нашел еще одно отличие. Посмотри это:

Sub Main()
    Dim X As New Derived
    Dim Y As Base = New Derived
    Console.WriteLine("X:" & X.Test())
    Console.WriteLine("Y:" & Y.Test())
    Console.WriteLine("X:" & CType(X, Base).Test)
    Console.WriteLine("X:" & X.Func())
    Console.WriteLine("Y:" & Y.Func())
    Console.WriteLine("X:" & CType(X, Base).Func)
    Console.ReadKey()
End Sub
Public Class Base
    Public Overridable Function Func() As String
        Return "Standard"
    End Function
    Function Test() As String
        Return Me.Func()
    End Function
End Class
Public Class Derived
    Inherits Base
    Public $$$ Function Func() As String
        Return "Passed By Class1" & " - " & MyBase.Func
    End Function
End Class

Если вы используете Overrides (где есть $$$) НЕТ СПОСОБА использовать Func в базовом классе, если определение экземпляра - Derived, и если определение является базовым, но экземпляр имеет производный тип.

Если вы используете Shadows, единственный способ увидеть Func в производном классе - это определить экземпляр как Derived и не переходить к методу базового класса (X.Test возвращает Standard). Я думаю, что это основной: если я использую Shadows, метод не будет перегружать базовый метод внутри базовых методов.

Это ООП-подход Overloads. Если я получаю класс и НИ В КОЕМ СЛУЧАЕ я хочу, чтобы метод был вызван, я должен использовать Overloads. Для экземпляров моих объектов нет возможности вернуть «Стандарт» (я думаю, кроме использования отражений). Я думаю, что intellisense немного запутал. Если я выделю Y.Func, будет выделен Func в базовом классе, но будет выполнен Func в производном классе.

С Shadows новый метод доступен только напрямую. Как например Overloads, но скрывая перегрузки базового класса (я думаю, что это ошибка, возвращаемая перед компиляцией, потому что вы можете вызвать ее с помощью приведения, например, неявного выполнения с использованием перегрузки).

Вот и ответ по коду.

Module Module1

    Sub Main()
        Dim object1 As Parent = New Child()
        Console.WriteLine("object1, reference type Parent and object type Child")
        object1.TryMe1()
        object1.TryMe2()
        object1.TryMe3()

        Console.WriteLine("")
        Console.WriteLine("")
        Console.WriteLine("object2, reference type Child and object type Child")
        Dim object2 As Child = New Child()

        object2.TryMe1()
        object2.TryMe2()
        object2.TryMe3()

        Console.ReadLine()
    End Sub

End Module

Public Class Parent

    Public Sub TryMe1()
        Console.WriteLine("Testing Shadow: Parent.WriteMe1")
    End Sub

    Public Overridable Sub TryMe2()
        Console.WriteLine("Testing override: Parent.WriteMe2")
    End Sub

    Public Sub TryMe3()
        Console.WriteLine("Testing Shadow without explicitly writing shadow modifier: Parent.WriteMe3")
    End Sub
End Class

Public Class Child
    Inherits Parent

    Public Shadows Sub TryMe1()
        Console.WriteLine("Testing Shadow: Child.WriteMe1")
    End Sub

    Public Overrides Sub TryMe2()
        Console.WriteLine("Testing override: Child.WriteMe2")
    End Sub

    Public Sub TryMe3()
    Console.WriteLine("Testing Shadow without explicitly writing shadow modifier: Child.WriteMe3")
    End Sub
End Class


'Output:
'object1, reference type Parent and object type Child
'Testing Shadow: Parent.WriteMe1
'Testing override: Child.WriteMe2
'Testing Shadow without explicitly writing shadow modifier: Parent.WriteMe3


'object2, reference type Child and object type Child
'Testing Shadow: Child.WriteMe1
'Testing override: Child.WriteMe2
'Testing Shadow without explicitly writing shadow modifier: Child.WriteMe3

Вы можете скопировать и вставить это и попробовать сами. Как видите, затенение является поведением по умолчанию, и Visual Studio предупреждает вас, когда затенение происходит без явного написания модификатора тени.

Примечание. Я никогда не использовал ссылку на базовый класс для дочернего объекта. Для таких случаев я всегда использую интерфейсы.

Тени могут быть очень полезны, если вы пишете оболочку вокруг существующего элемента управления.

Например, вокруг поля со списком. Затеняя AutoCompleteSource, вы можете предотвратить его установку на недопустимое значение для вашего специального вида комбинированного списка, даже если он приведен к обычному комбинированному списку. Или выполните предварительную обработку, прежде чем использовать mybase.AutoCompleteSource = value в свойстве теневого копирования.

Тени используются редко, но это правда. Более того, вы не можете переопределить общий (статический) метод. Таким образом, вы должны затенять общий метод, если хотите его «переопределить».

VB использует более продвинутые концепции ООП, чем C#, для использования переопределения в производном классе в C# вы ДОЛЖНЫ пометить метод как «vitrual», Shadow позволяет делать перегрузку без этого.

Прочтите документацию MS об этом https://docs.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/declared-elements/differences-between-shadowing-and-overriding

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