programing

VB.NET의 '그림자' 대 '덮어쓰기'

jooyons 2023. 5. 20. 10:47
반응형

VB.NET의 '그림자' 대 '덮어쓰기'

섀도와 오버라이드 두 키워드의 의미는 무엇입니까?그들이 무엇을 하고 어떤 맥락에서 하나 또는 다른 것이 더 좋습니까?

재정의가 일반 한정자입니다.자식 클래스가 이러한 방식으로 기본 클래스 함수를 재정의하는 경우, 기본 클래스 또는 자식 클래스 참조를 사용하여 자식 개체를 참조하는 방법에 관계없이 호출되는 것은 자식 함수입니다.

반면에 하위 클래스 함수가 기본 클래스 함수를 그림자로 표시하는 경우 기본 클래스 참조를 통해 액세스되는 하위 개체는 하위 개체임에도 불구하고 해당 기본 클래스 함수를 사용합니다.
하위 함수 정의는 일치하는 하위 참조를 사용하여 하위 개체에 액세스하는 경우에만 사용됩니다.

그림자를 드리우는 것은 아마도 여러분이 생각하는 것처럼 하지 않을 것입니다.

다음 클래스를 고려합니다.

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

나는 이것이 매우 위험한 행동이고 문서에서 거의 언급되지 않았습니다.

오버라이드를 사용한 경우에도 마찬가지입니다.

그래서 그림자에 대한 합법적인 사용이 있지만, 여러분이 하고 있는 일은 그들 중 하나가 아니며 그것은 피해야 합니다.

재정의 - 메서드에 대한 대체 기능을 확장하거나 만듭니다.

예:창의 그림판 이벤트 기능을 추가하거나 확장합니다.


    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

그림자 - 상속된 메서드를 재정의하고 해당 유형의 인스턴스에 있는 모든 클래스에 대해 메서드를 강제로 사용합니다.즉, 메서드가 오버로드되지 않고 재정의되며 기본 클래스 메서드를 사용할 수 없으므로 클래스에 선언된 함수를 사용해야 합니다.섀도는 기본 클래스 메서드를 수정하더라도 메서드가 삭제되지 않도록 메서드의 정의를 보존하거나 유지합니다.

예:모든 "B" 클래스가 홀수볼을 사용하도록 강제합니다. A 클래스 Add 메서드를 수정해도 B의 추가에 영향을 주지 않도록 정의를 추가합니다. (모든 기본 클래스 "Add" 메서드를 숨깁니다.)A에게 전화할 수 없습니다.B의 인스턴스(instance)에서 (x, y, z)를 추가합니다.


    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

때때로 작은 예는 기술적인 방법으로 차이를 이해하는 데 도움이 됩니다.

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

섀도잉의 예:타사 구성 요소에서 함수를 사용하려고 하지만 해당 함수가 보호된다고 가정합니다.간단한 상속을 통해 이 제약 조건을 무시하고 기본 함수를 호출하는 음영 함수를 노출할 수 있습니다.

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

"shadows" 키워드는 기본적으로 "이 개체에 액세스하는 사용자가 이 개체 유형 또는 해당 개체의 하위 유형 중 하나임을 알고 있으면 이 구성원을 사용하고, 그렇지 않으면 기본 구성원을 사용하십시오."라고 말합니다.이것의 가장 간단한 예는 기본 클래스 ThingFactory일 수 있습니다. 여기에는 Thing을 반환하는 "MakeNew" 메서드와 "MakeNew" 메서드가 항상 파생된 유형의 Car를 반환하는 ThingFactory에서 파생된 클래스 CarFactory가 포함됩니다.루틴이 보유한 ThingFactory가 발생한다는 것을 알고 있다면, 특히 CarFactory가 될 것입니다. 그러면 Shadowed CarFactory가 사용됩니다.반환 유형을 차량으로 지정할 수 있는 MakeNew(있는 경우).루틴이 자신의 ThingFactory가 실제로 CarFactory인지 모를 경우 음영이 없는 MakeNew(내부적으로 보호된 재정의 가능한 MakeDerived)를 사용합니다.사물 방법).

참고로 섀도의 또 다른 유용한 사용은 파생 클래스가 더 이상 작동하지 않는 보호된 메서드에 액세스하지 못하도록 하는 것입니다.새 클래스를 할당하는 것 외에 파생 클래스에서 멤버를 숨기는 방법은 없지만 해당 이름으로 새 보호된 빈 클래스를 선언하여 파생 클래스가 보호된 멤버와 함께 작업하는 것을 방지할 수 있습니다.예를 들어 개체에 대해 MemberwiseClone을 호출하여 이를 해제하는 경우 다음을 선언할 수 있습니다.

보호 그림자 클래스 멤버별 복제클래스 종료
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 제어 클래스에서 제 클래스를 상속합니다.이 시점에서 저는 코드를 "순수"하게 만들거나 이해하기 쉽게 만드는 것에 직면해 있습니다.이 컨트롤의 클라이언트는 단순히 컨트롤을 호출하려고 합니다.집중하고() 아마 신경 쓰지 않을 것입니다.나는 이 방법을 FocusSearchText() 또는 Focus2 등으로 명명할 수 있었지만 클라이언트 코드에 대해서는 위의 내용이 훨씬 더 간단하다고 생각합니다.그런 다음 클라이언트가 이 컨트롤을 기본 클래스로 캐스팅하고 포커스를 호출하면 내 코드가 삭제되지 않는 것은 사실입니다.하지만 그것은 꽤 멀리 떨어져 있습니다.

결국 그것은 심판 판정으로 귀결되고, 당신은 그 판정을 내려야 할 것입니다.

최근 MSDN 링크입니다. 섀도잉과 오버라이드의 차이점

섀도잉은 파생 클래스에 이미 정의한 구성원을 소개하는 후속 기본 클래스 수정으로부터 보호합니다.일반적으로 다음과 같은 경우 섀도잉을 사용합니다.

같은 이름을 사용하여 요소를 정의하도록 기본 클래스가 수정될 수 있습니다.*

요소 유형 또는 호출 시퀀스를 자유롭게 변경할 수 있습니다.*

(범위 및 유형과 관련하여 사용법을 아직 조사하지 않았습니다.)

자, 여기 코드에 의한 답이 있습니다.

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에서 경고를 표시합니다.

참고: 하위 개체에 대한 기본 클래스 참조를 사용한 적이 없습니다.그런 경우에는 항상 인터페이스를 사용합니다.

섀도를 사용하면 재정의로 수행할 수 없는 특정 작업을 수행할 수 있습니다.

내 경우에는:일반 기능을 가진 테이블 클래스가 여러 개 있지만 컬렉션 자체가 서로 다른 유형입니다.

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

그렇다면 구체적인 예는 다음과 같습니다.

Public Class WidgetTable
Inherits GenericTable
Protected Friend Shadows Property Contents As System.Collections.Generic.List(Of Widget)
    ... stuff is inhereted ...
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

재정의($$$가 있는 경우)를 사용하는 경우 인스턴스의 정의가 파생된 경우와 정의가 기본이지만 인스턴스가 파생된 유형인 경우에도 Funcon 기본 클래스를 사용할 방법이 없습니다.

Shadows를 사용하는 경우 파생 클래스로 Func를 볼 수 있는 유일한 방법은 기본 클래스(X) 메서드에 전달하지 않고 인스턴스를 파생으로 정의하는 것입니다.검정에서 표준)을 반환합니다.이것이 가장 중요한 것 같습니다: Shadows를 사용하면 기본 메소드 내부에 기본 메소드가 오버로드되지 않습니다.

오버로드의 OOP 접근 방식입니다.클래스를 파생하고 어떤 경우에도 메서드가 호출되기를 원하는 경우 오버로드를 사용해야 합니다.개체의 경우 "표준"을 반환할 방법이 없습니다(반영을 사용하는 경우 제외).저는 지능이 약간 혼란을 일으킨다고 생각합니다.Y를 강조 표시하면.Func, 기본 클래스로 Func가 강조 표시되지만 파생 클래스로 Func가 실행됩니다.

Shadows를 사용하면 새 메서드에 직접 연결할 수 있습니다.오버로드와 같이 기본 클래스의 오버로드를 숨깁니다(오버로드를 사용하여 암묵적으로 수행하는 것과 같이 캐스트를 사용하여 호출할 수 있기 때문에 컴파일 전에 반환된 오류라고 생각합니다).

그림자는 기존 컨트롤 주위에 래퍼를 작성하는 경우 매우 유용할 수 있습니다.

예를 들어 콤보 상자 주위에 있습니다.그림자를 드리움으로써.AutoCompleteSource일반 콤보 상자에 캐스팅된 경우에도 특수한 종류의 콤보 상자에 대해 잘못된 값으로 설정되는 것을 방지할 수 있습니다.또는 사용하기 전에 사전 처리를 수행합니다.mybase.AutoCompleteSource = value그늘진 땅에서

VB는 C#보다 고급 OOP 개념을 사용하며, C#의 파생 클래스에서 재정의를 사용하려면 메서드를 "가상"으로 표시해야 합니다. 섀도를 사용하면 이 없이 오버로드할 수 있습니다.

https://learn.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/declared-elements/differences-between-shadowing-and-overriding 에 대한 MS 설명서 읽기

그림자의 사용은 드물지만 사실입니다.또한 공유(정적) 메서드를 재정의할 수 없습니다.따라서 공유 메서드를 "재지정"하려면 공유 메서드를 그림자로 표시해야 합니다.

저는 짐의 말에 동의합니다.나도 그림자의 합법적인 용도를 찾은 적이 없습니다.보통 제가 그것을 본다면, 코드의 하위 섹션은 약간의 리팩터링이 필요하다고 생각합니다.

소스 코드에 대한 제어권이 없는 어셈블리에서 메서드를 섀도로 만들 수 있도록 하기 위해서라고 생각합니다.이 경우, 부모 클래스를 리팩터링하는 것은 불가능할 것입니다.

사용하고 싶었습니다.System.Web.HttpContext.Current.Response대신에Response.redirect그리고 코드화하기 위한 편리함이 필요했습니다.Response.redirect다음 이름의 읽기 전용 속성을 정의했습니다.Response기본 클래스에서 원본을 음영 처리합니다.이 속성은 재정의할 수 없으므로 재정의를 사용할 수 없습니다.매우 편리합니다:)

저는 Shadows를 OOP 개념으로 생각하지 않습니다.재정의는 상위 클래스에 선언된 메서드/속성 등에 대해 새 기능 또는 추가 기능을 제공하고 있음을 나타냅니다.섀도는 컴파일러를 속여서 상위 메서드/속성 등이 존재하지도 않는다고 생각하게 만듭니다.

그림자는 필요 없습니다.재정의를 고수합니다.VB가 수년간 제공해 온 이러한 유용한 작은 "기능"은 어느 순간에는 항상 사용자에게 슬픔을 안겨줍니다.

언급URL : https://stackoverflow.com/questions/463209/shadows-vs-overrides-in-vb-net

반응형