2013-04-10 1 views
4

뭔가 이상한 점이있어서 재미 있었고 설명을 좋아할 것입니다. 이 질문은 의미하지 않는다동일한 클래스의 공유 함수에서 호출 할 때 오버로드 된 개인 공유 함수에 액세스 할 수없는 이유

편집은 그것을 해결하기 위해 수행해야 무엇으로 대답한다. 나는 그 수정 사항을 안다. 컴파일러가 왜 그렇게하는지에 대한 설명이 필요합니다. 전의. 이 시나리오에서 개인 기능이 고려되지 않았습니까?

문제

내가 whatis는라는 공공 공유 (정적) 함수가있는 클래스가 있습니다. WhatIs는 개체 컬렉션이있는 매개 변수를 사용합니다. 코드는이 컬렉션을 반복하고 개체가 무엇인지 유형과 일치하는 매개 변수가있는 WhatIs 함수를 호출합니다.

실행되면 InvalidCastException 예외는 시작된 WhatIs 함수를 호출하려고하므로 실행되지 않습니다.

이상하게 들리지만 개인 공유 기능을 공개 공유로 변경하면 나에게 이상한 점이 있습니다.

개체를 명시 적으로 캐스팅 할 때도 함수가 비공개 인 경우에도 작동합니다.

무엇?! 누군가가

코드

배짱이 설명해주십시오 :

Public Class House 
    Public Property Furniture As ICollection(Of Object) 

    Public Sub New() 
     Furniture = New List(Of Object) 
    End Sub 
End Class 

Public Class Chair 
    Public Property IsComfortable As Boolean 
End Class 

Public Class Table 
    Public Seats As Integer 
End Class 

Public Class HouseExaminer 
    Public Shared Function WhatIs(thing As House) As String 
     Dim isA As String = "a house that contains " 

     For Each item In thing.Furniture 
      isA &= WhatIs(item) 
     Next 

     Return isA 
    End Function 

    Private Shared Function WhatIs(thing As Chair) As String 
     Return "a " & If(thing.IsComfortable, "comfortable", "uncomfortable") & " chair " 
    End Function 

    Private Shared Function WhatIs(thing As Table) As String 
     Return "a table that seats " & thing.Seats & " iguanas" 
    End Function 
End Class 

테스트

Imports System.Text 
Imports Microsoft.VisualStudio.TestTools.UnitTesting 
Imports stuff 

<TestClass()> 
Public Class HouseExaminerTests 

    <TestMethod()> 
    Public Sub TestWhatIs() 
     Dim given As New House() 
     Dim expected As String 
     Dim actual As String 

     given.Furniture.Add(New Chair() With {.IsComfortable = True}) 
     given.Furniture.Add(New Table() With {.Seats = 4}) 

     expected = "a house that contains a comfortable chair a table that seats 4 iguanas" 
     actual = HouseExaminer.WhatIs(given) 

     Assert.Equals(expected, actual) 
    End Sub 
End Class 

결과

,

디버그 테스트 당신이 얻을 : InvalidCastException이 메소드 호출이 실패 때문에 '공개 공유 기능 whatis는 문자열로 (stuff.House로서 것)'이 인수로 호출 할 수 없습니다 :

인수 일치하는 매개 변수 '일' 'Chair'에서 'House'로 변환 할 수 없습니다.

이러한 변경으로 인해 효과가 있지만 왜 그렇습니까?!

메이크업 안에 공공

변화를 공개, 다시 실행 테스트에 HouseExaminer의 개인 공유 기능.스포일러, 그것은 그것을

가 명시 적으로

isA &= WhatIs(item) 

If TypeOf item Is Chair Then isA &= WhatIs(CType(item, Chair)) 
If TypeOf item Is Table Then isA &= WhatIs(CType(item, Table)) 

다시 실행 테스트와

, 그리고 u는 무엇을 알 수 있습니까 대체 객체를 다시 민간에

변화를 캐스팅 작동 작품

+0

옵션 추가 Strict On을 선택한 다음 모든 가구에서 지원되는 인터페이스를 정의합니다 (예 : iFurniture이며 객체가 문자열 반환 함수를 정의해야합니다. – Amegon

+0

w.brian의 대답에 대한 반응을 참고하십시오 –

답변

4

첫째, 암시 적 전환이 켜져 있습니다. 그것이 문제의 시작입니다. 둘째, FurnitureList(of Object)으로 정의합니다. 처음으로 WhatIs에 전화가 왔습니다. 컴파일러는 을 전달할 때 사용할 오버로드를 가장 잘 추측합니다.은 을 반복 할 때 간단히 Object으로 표시되며 WhatIs 메서드의 공용 정적 버전이 가장 적합하다고 판단합니다. 암시 적으로 ObjectHouse으로 변환하려고 시도하며 필연적으로 실패합니다.

왜 주조가 작동합니까? 사용할 오버로드를 결정할 때 추측 작업이 필요하기 때문입니다.

이야기의 도덕적 인 의미는 다음과 같습니다. 컴파일러를 추측하지 마십시오. 암시 적 변환은 까다로운 버그로 이어질 수 있습니다.

: 왜 컴파일러는 다른 오버로드 된 기능을 볼 수 없습니까?

컴파일러는 컴파일 시간이 인 에서 사용할 정확한 오버로드를 결정해야합니다. 런타임에서 사용할 오버로드를 결정할 때까지 기다리지 않으므로 가장 적합한 오버로드를 결정하기 위해 객체의 유형을 검사하는 고급 스러움이 없습니다.

컴파일러는 기술적으로 (암시 적 변환이 켜져있는 상태에서) List(Of Object)이라는 것을 알고 있기 때문에 세 가지 오버로드가 모두 "적절한"것으로 간주되지만 컴파일러는 하나를 선택해야합니다. 가능한 과부하 후보를 순위 지정하고 private 것보다 먼저 public 버전을 선택합니다.

  • 에 엄격한

  • +0

    List (of object)는 의도적으로 수행됩니다. 바로 그 곳에서 진짜 바보가 나옵니다. 일반적으로 나는 더 구체적 일 것이다. 그러나 이것은 XSD 생성 클래스들 때문에 현실 세계에서 나타 났으므로 다른 사람들이 뛰어 다니는 것이 될 수도있다. –

    +0

    그리고 나는 interaces/abstract 클래스와 같은 쉬운 수정이 있다는 것을 알고 있습니다. 이것은 더 많은 것을 의미했습니다. 컴파일러는 왜이 시나리오에서와 같은 방식으로 행동합니까? –

    +0

    +1 이야기의 사기 만합니다. 암시 적 변환이 수행 될 때 컴파일러가이 시나리오에서 비공개를 볼 수없는 이유에 대한 괴짜 대답을 기다리고 싶습니다. –

    2
    1. 사용 항상

      옵션 당신은 다른 parameterTypes와 함께, 이름에 동일한 방법을 추가하여 좀 더 유연 할 수 없습니다.

    업데이트

    Private Function ShowMe(data As Integer) As String 
        Return data.ToString 
    End Function 
    
    Private Function ShowMe(data As String) As String 
        Return data 
    End Function 
    
    Private Function ShowMe(data As Double) As String 
        Return data.ToString 
    End Function 
    
    Dim bla As New List(Of Object) 
    

    당신이 다음

    bla.Add(12) 
        bla.Add("hi") 
        bla.Add(1.2) 
        Dim text As String 
        text = ShowMe(bla(0)) 
        text = ShowMe(bla(1)) 
        text = ShowMe(bla(2)) 
    

    를 호출하는 경우 다음 컴파일러는 항상 올바른 방법으로 선택되어 있지 않기 때문에 올바른 방법은 존재하지 않는다고 불평 할 것이다 형식을 확인하는 대신 정의에 따라 컨테이너가 정의 된 유형이 선택됩니다.

    Private Function ShowMe(data As Object) As String 
        Return data.ToString 
    End Function 
    

    이것은 모든 정수, double 및 문자열에 대해 호출됩니다. 사용할 수없는 경우 일종의 자동 변환을 수행 할 수있는 몇 가지 방법이 사용됩니다. 이유는 정수를 플로트에 넣거나 숫자를 문자열에 넣을 수 있기 때문입니다.

    한 가지 방법은 그 형태를 확인하는과 explizit 형식 변환을

    For Each ele As Object In bla 
         If TypeOf ele Is Integer Then 
          text = ShowMe(CInt(ele)) 
         ElseIf TypeOf ele Is Double Then 
          text = ShowMe(CDbl(ele)) 
         Else 
          text = ShowMe(CStr(ele)) 
         End If 
        Next 
    

    을하지만이 여전히 깨끗하지 않습니다 것입니다. 모든 객체가 지원해야하는 속성에 액세스하려면 컨테이너에 넣고 해당 속성이 존재 함을 보증하는 것으로 유형을 정의하십시오.

    +0

    on pt 1, agree. 이것은 이론적 목적을 위해 행해졌 다. 태평양 표준시 2에서는 동일한 이름, 다른 매개 변수에는 아무런 문제가 없습니다. 실제로 오버로드가 무엇인지 확실하지 않으므로 점을 얻습니다. –

    +0

    과부하에는 문제가 없지만 _unfortunately_가 작동하지 않으면 올바른 선택입니다. 주어진 매개 변수의 실제 유형을 검사하여 피팅 오버로드 된 메서드를 호출합니다. 답변 – Amegon

    +0

    의 업데이트를 참조하십시오. 흥미로운 점. 모든 기능이 비공개이므로 아무 것도 사용되지 않습니다. 하아! pub/private에 따른 순위조차도 암시 적 변환에 대한 privates를 무시합니다. 함께 대답 해 줘서 고마워. 정확히 내가 뭘 찾고 있었는지는 모르지만, +1하면 좋은 보완 물을 가져 왔습니다. –

    관련 문제