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





Я бы не стал считать Shadows действительно концепцией ООП. Переопределения означает, что вы предоставляете новые или дополнительные функции для метода / свойства и т. д., Которые были объявлены в классе-предке. Тени действительно обманывают компилятор, заставляя его думать, что родительский метод / свойство и т. д. Даже не существует.
Мне не нужны тени. Придерживайтесь переопределений. Эти полезные маленькие «функции», которые VB предоставлял годами, всегда в конечном итоге в какой-то момент вызывают у вас горе.
-1. Тени - отличное и полезное понятие. Он скрывает все методы базового класса с тем же именем и заставляет использовать объявленный метод. Переопределения не скрывают все методы базового класса.
Как только вы затеняет унаследованный метод, класс больше не может считаться истинным потомком его предка. ИМХО, это не совсем ООП, и я сомневаюсь в дизайне приложения, которое могло бы привести к этому пути. В некоторых случаях это может быть необходимо, но обычно нет.
Я согласен, однако, вопрос заключается в том, что они делают и в каком контексте они используются, а не в том, считает ли кто-нибудь их концепциями ООП.
-1 Эквивалент C# - «новый», поэтому частная новая строка Test () {...} делает то же самое. Не просто "проблема" vb.net
Вы заслуживаете -2, сначала за неуважение к очень полезному слову Shadows, а затем за незнание основных ключевых слов языка, которым вы так гордитесь, "оскорбление" других языков.
-1; как утверждали другие, это на самом деле не отвечает на вопрос.
-1 за то, что сказать «Тени» - плохая черта только потому, что вы не понимаете ее значения.
Я не уверен, стоит ли голосовать против этого ответа, потому что все исправления от других отрицателей настолько полезны, что я бы не хотел, чтобы отвечающий отмечал ответ удаленным.
Я согласен. Люди стали настолько агрессивными в голосовании против людей, что говорят все, что им не нравится. Разногласия - полезные люди!
Я согласен с Джимом. Я также никогда не находил законного применения Shadows. Обычно, если я это вижу, я предполагаю, что этот подраздел кода нужно немного реорганизовать.
Я полагаю, что это так, чтобы вы могли скрыть метод из сборки, в которой у вас нет контроля над исходным кодом. В этом случае рефакторинг родительского класса будет невозможен.
-1. Если тени используются правильно, в рефакторинге нет необходимости.
Я бы поставил под сомнение объектно-ориентированный дизайн, который во многом полагается на использование методов затенения. Если производный класс действительно является более конкретным типом базового класса, он обычно должен только расширять функциональные возможности, а не удалять функциональные возможности.
Переопределения - расширение или создание альтернативных функций для метода.
Пример: добавить или расширить функциональность события 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
Это противоречит нескольким принципам объектно-ориентированного программирования, поэтому я хотел бы привести пример практического использования (приведенное выше - нет). Вот что я имею в виду под «новичком»: это, по сути, ненужный механизм, который создает плохой, неподключаемый интерфейс. Полная противоположность хорошему объектно-ориентированному дизайну.
В частности, ваш код не будет работать с полиморфными экземплярами A: Dim x As A = new B() : x.Add(1, 2).
Я согласен с Джимом, Чадом и Конрадом. Тени против ОО.
К счастью для вас, эта ветка посвящена тому, что они делают и в каком контексте используются.
Отменяет - более нормальный квалификатор. Если дочерний класс переопределяет функцию базового класса таким образом, то независимо от того, как ссылается дочерний объект (с использованием ссылки на базовый класс или дочерний класс), вызывается дочерняя функция.
С другой стороны, если функция дочернего класса Тени является функцией базового класса, тогда дочерний объект, доступ к которому осуществляется через ссылку базового класса, будет использовать эту функцию базового класса, несмотря на то, что он является дочерним объектом. Определение дочерней функции используется только в том случае, если доступ к дочернему объекту осуществляется с использованием соответствующей дочерней ссылки.
Человек, задавший вопрос, кажется порядочным пользователем SO, так почему этот ответ не является принятым ответом?
Это технически правильный ответ, но следует отметить опасности использования Shadows (vb.net) / new (C#), как в этой ориентированной на C# статье msdn.microsoft.com/en-us/library/ms173153%28v=vs.80%29.aspx и в этом прекрасном SO-QA stackoverflow.com/questions/13162542/…
Но если один из Shadows является участником с одним и тем же участником, мы круты, верно? Вы спросите, зачем это нужно? При наследовании и реализации одного и того же события ... По крайней мере, я вижу единственный способ решить эту проблему: stackoverflow.com/questions/14825021/…
Пример затенения: предположим, что вы хотите использовать функцию в стороннем компоненте, но функция защищена. Вы можете обойти это ограничение с помощью простого наследования и предоставления теневой функции, которая в основном вызывает свою базовую функцию:
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
Имхо, это очень опасное поведение, о котором почти не упоминается в документации.
Если бы вы использовали переопределение, они были бы такими же.
Таким образом, хотя есть законное использование теней, скорее всего, все, что вы делаете, не относится к их числу, и этого следует избегать.
Хорошая иллюстрация того, где вы можете столкнуться с проблемами при использовании этой функции. Обратите внимание, что этот эффект также возникает, если вы перебираете коллекцию базового класса с экземплярами унаследованного класса в коллекции.
Ключевое слово «shadows» по существу говорит: «Если тот, кто обращается к этому объекту, знает, что он принадлежит к этому типу или к одному из его потомков, используйте этот член; в противном случае используйте базовый». Простейшим примером этого может быть базовый класс ThingFactory, который включает метод MakeNew, который возвращает Thing, и класс CarFactory, производный от ThingFactory, чей метод MakeNew всегда возвращает Thing, который будет иметь производный тип Car. Если подпрограмме известно, что ThingFactory, который она содержит, является, в частности, CarFactory, то она будет использовать теневой CarFactory.MakeNew (если он существует), который может указывать возвращаемый тип как Car. Если подпрограмма не знает, что ее ThingFactory на самом деле является CarFactory, она будет использовать не затененный MakeNew (который должен вызывать внутренний защищенный переопределяемый метод MakeDerivedThing).
Между прочим, еще одно хорошее использование теней - предотвратить доступ производных классов к защищенным методам, которые больше не будут работать. Невозможно просто скрыть член от производных классов, кроме назначения нового, но можно запретить производным классам делать что-либо с защищенным членом, объявив новый защищенный пустой класс с этим именем. Например, если вызов MemberwiseClone для объекта приведет к его поломке, можно объявить:
Protected Shadows Class MemberwiseClone End ClassNote 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, чтобы «избавиться» от перегрузки, которую вы не можете использовать.
Иногда небольшой пример действительно помогает понять разницу с технической точки зрения.
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
Вы можете подумать о том, чтобы принять ответ @Nика, так как он намного полезнее. (Кроме того, довольно странно иметь серый ответ наверху ...)