Why overloaded private shared functions are not available when calling from a shared function in the same class

Found something that I was interested in, and I would have liked the explanation.

Edit

In this question there should be no answer what needs to be done to correct it. I know the fixes. I want to explain why the compiler does what it does. Ex. Are private functions considered in the light of this scenario?

Problem

I have a class that has a publicly shared (static) function called WhatIs. WhatIs accepts a parameter that has a set of objects. the code iterates over this collection and calls the WhatIs function, which has the type of matching parameter, what the object is.

On execution, an InvalidCastException is thrown because the execution tries to call the WhatIs function that launched it, and not the one that was provided.

This is strange, but it was strange for me when you changed private general functions to general, and then worked perfectly.

Even clearer when explicitly casting an object, it works even if the function is private.

What?! someone explain

code

guts:

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 

check

 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 

result

debug the test, and you get the following: InvalidCastException The method error is caused by the "Public Shared Function WhatIs (thing like stuff.House) because String cannot be called with these arguments:

The parameter of coincidence of arguments of the “thing” cannot be transformed from the “chair” to “home”.

These changes make it work, but why ?!

make em public

change your personal shared features in HouseExaminer to a public, retest. spoiler, it works

obviously throws objects

change them to private then replace

 isA &= WhatIs(item) 

with

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

retest and what do you know it works

+4
source share
2 answers

First, it looks like you have included implicit conversions. This is the beginning of the problem. Secondly, you define Furniture as a List(of Object) . Your first WhatIs call succeeds. The compiler makes the best guess about what overload should be used when passing what it sees simply to Object , as it thing.Furniture through thing.Furniture , and it determines that the public static version of the WhatIs method is the most suitable. He then tries to implicitly convert Object to House and inevitably fails.

Why does casting work? Because to determine which overload should be used, you need to guess.

The moral of the story: do not make the compiler guess. Implicit conversion can lead to complex errors.

Change Why doesn't the compiler see other overloaded functions?

The compiler must determine the correct overload to use at compile time. It does not wait for runtime to determine which overload to use, and therefore does not have the luxury of checking the type of object to determine the most suitable overload.

Since the compiler only knows that Furniture is a List(of Object) , technically (with implicit conversion turned on), all three overloads are considered “appropriate”, but the compiler must choose one. It evaluates possible overload candidates and selects the public version before private .

+4
source
  • Use always

    Strict On Option

  • You cannot make it more flexible by adding methods equal in name, just with different types of parameters.

Update

 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) 

if you then call

  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)) 

then the compiler will always complain that the correct method does not exist, because the correct method is not selected by checking the type, instead it is selected by the definition for which the container type is determined.

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

this will be called for all integers, pairs and strings. If it is not available, some methods are used that can perform some kind of automatic conversion. This is why you can put an integer in a float or put a number in a string.

One way is to check its type and perform a conversion of type 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 

But it is still not so clean. If you want to access the properties that all objects must support, then put them in a container and define the type as something that ensures that these properties exist.

+2
source

All Articles