Why can't I have two methods with the same parameters but different returns? - vb.net

.net allows...
Public Function One(A as Integer) As String...
Public Function One(B as String) As String...
It figures out which one to call by looking at the Type of the parameters, like...
Dim A As String = One(5)
Ok, so why can't you do this...
Public Function One(A as Integer) As String...
Public Function One(B as Integer) As Integer...
The same amount of information is available to the compiler...
Dim A As Integer = One(5) ' should know to call the second version
The specific problem I'm trying to solve is to return the Values in a Dictionary(Of Integer, MyClass) so that it is visible to COM Interop. To do that I simply return the .Values as IEnumerable. But then I lose the type inside my own code, which is a PITA. If I could have two methods I could have one that returns IEnumerable and another that returns List(Of MyClass) and the API would be the same in both places. I could have two different method names, but that kind of defeats the purpose.
I'm open to any solution that fixes the underlying problem... is there a single type I can return that avoids all the DirectCast in my own code, while still being visible to COM Interop?

Short answer : because the return type isn't included in the method's signature
the relevant part of the spec
The following are not part of a member's signature, and hence cannot be overloaded on:
Modifiers to a type member (for example, Shared or Private).
Modifiers to a parameter (for example, ByVal or ByRef).
The names of the parameters.
The return type of a method or the element type of a property.

Related

VBA: function that takes multiple types of input?

I have some user-defined types and a function for each that takes those types and does something to them.
The thing is though, I'd like to write one, generic function that takes any of those types, and then just uses TypeName to figure out which one it is, and treats it like it needs to.
How do I do this? I tried taking the parameter as Function Foo(Param As Object), but then it fails when I try to pass in a user-defined type into the function.
User Defined Types (UDT) are not classes (they are similar to Structures in C or Records in Pascal), therefore instances of an UDT are not objects - that's the reason you can not use them as an argument to your function foo.
VBA has a universal data type Variant. So when you have Function Foo(Param As Variant), you can pass anything to the function, Foo 3 or Foo ActiveSheet or Foo "Hello world". Anything, except a UDT... If you try so, you will get a compiler error stating "Only user defined types defined in public object modules can be coerced to or from a variant or passed to late-bound functions.":
Public Type tMyType
i As Integer
s As String
End Type
Sub Test
Dim bar as tMyType
' Compiler complains
foo bar
Dim myUniversalVariant as Variant
' Compiler complains also
myUniversalVariant = bar
End Sub
The official documentation of Variant states that "Variant types now support user-defined types.", however at least on Excel 2016 this is not working (or at least I was not able to do so).
Your best bet is to use Classes. If you're lazy, just create a class module (per Type) and put all members of the type as public members, nothing more needed (I will not start to describe the pros and cons of getter and setter). You just need to remember that now you have to use the New statement to create and Set to assign an instance.
In class module (I named it clsMyType):
public i As Integer
public s As String
In the regular module:
Sub Test
Dim bar as clsMyType
Set bar = new clsMyType
foo bar
Dim myUniversalVariant as Variant
Set myUniversalVariant = bar
foo myUniversalVariant
End Sub
Now depending if your function wants to receive only object or also other stuff (like integers or strings), parameter type can be Variant or Object
Function foo(Param as Object)
Debug.Print TypeName(Param)
End Function

How can I pass a variable number of arguments in a Func type declaration?

I have to implement a control in VB.Net where one of the properties is a function: basically, the user will set a certain function as an argument during the creation of the control, and the control will do something accordingly. A short example:
' Signature of the property
Public Property VarMethod As Func(Of DataRow, String)
' Assigning the function to the control
control.VarMethod = AddressOf ToBeCalled
' Function that should be called
Private Function ToBeCalled(row as DataRow) As String
Something like that. I'd like to alter the property so that it can accept functions with a variable number of arguments, in case the row isn't enough for the function: basically, it should work even with functions like, for example, ToBeCalled(row as Datarow, index as Integer). I thought I could do something with ParamArray, but Func doesn't seem to accept it in the definition: adding a Object() to the definition, on the other hand, forces me to insert the secondary parameters every time. Do you know if there's a way to define the type Func so that it works the way I want it to? Thanks

Opposite to a Structure?

I'm sure there is an answer to this somewhere but I'm clearly using the wrong terminology in my searches, so I apologise in advance for this inevitably being a duplicate.
Take the function CType. Clearly I can cast (or at least try) a given object to a given reference type. The function will not work if trying to cast to a structure, i.e.
CType(myObject, Integer)
...will generate a compiler error. This I'm sure most often crops up when working with generics:
Public Function GetResults(Of T)() As T
Dim instance As T
Return CType(GetData(instance), T)
End Function
Public Function GetData(ByVal param As myClass) As myClass
'do stuff
Return param
End Function
Public Function GetData(byval param As Integer) As Integer
'do stuff
Return param
End Function
Public Function GetResults(ByVal param As Object) As Object
Throw New NotImplementedException
End Function
Probably not the best of examples but hopefully shows what I mean. The following will work:
Dim result = GetResult(Of myClass)
The following will fail on the CType
Dim result = GetResult(Of Integer)
I'm not a big fan of using exceptions/Try-Catch if logic can be applied, so although I could Try-Catch the CType, I'd rather find a way to route it through different code. I know with Generics I can use
Public Function GetResults(Of T As Structure) As T
What is the opposite? I want only reference types so that CType doesn't fail... I can't overload the T As Structure with a plain T because it considers them identical signatures, so surely there's a keyword I'm missing somewhere? ^^
Long question, probably only requries a one word answer (sorry)... Thanks in advance!
Public Function GetResults(Of T As Class) As T

Byref New Object. Is it okay top pass New Object as "byref"

Below I tried to do an Example:
Public Function UserData(ByVal UserDN As String) As DataTable
Dim myTable As DataTable = UserData_Table()
Dim dr As DataRow
dr = myTable.NewRow()
SplitOU2(UserDN, dr("OUDN"), dr("Organisation"), New Object)
dr("UserDN") = UserDN
myTable.Rows.Add(dr)
Return myTable
End Function
Below is the called method:
Friend Sub SplitOU2(ByVal inDN As String, ByRef OUDN As Object, ByRef Organisation As Object, ByRef VerksamhetTyp As Object)
By doing this I can skip to declare the in this example "useless" variable
Dim VerksamhetTyp as Object = "".
Perhaps it looks a little ugly but to have to declare unused variables can also be confusing.
Summary: Check whether or not the method really needs those parameters to be ByRef. Also check that you really don't care about anything it does to the parameters. After scrupulous checking, it's okay to do this - nothing "bad" will happen in terms of the CLR, because it's just a compiler trick under the hood.
Well, VB (unlike C#) will let you do this. Behind the scenes it's effectively creating a new variable and passing it by reference - after all, it has to for the method to be called properly. However, I'd say this is usually a bad idea. The point of ByRef is that you use the value after it's been set within the method.
Do you really need all those parameters to be ByRef in the first place? If you find yourself doing this a lot for a particular method, you could always write a wrapper method which called the original one, but didn't have the ByRef parameters itself.
(I usually find that methods with a lot of ByRef parameters indicate either a lack of understanding of reference types in .NET, or that the parameters should be encapsulated in their own type.)
Having said all of this, it's not always incorrect to ignore the value of a ByRef argument after calling the method. For example, if you just want to know whether or not some text can be parsed as an integer, then using Int32.TryParse is reasonable - but only the return value is useful to you.
The reason that I consider to use this has to do with that the method has even more parameters and that different operation overloads gets the same signature ….
The fact that it works is quite fun and somthing I became awarae óff by chance ...

Iterate through generic list of unknown type at runtime in VB.Net

Does anyone know how to iterate over a generic list if the type of that list isn't known until runtime?
For example, assume obj1 is passed into a function as an Object:
Dim t As Type = obj1.GetType
If t.IsGenericType Then
Dim typeParameters() As Type = t.GetGenericArguments()
Dim typeParam As Type = typeParameters(0)
End If
If obj is passed as a List(Of String) then using the above I can determine that a generic list (t) was passed and that it's of type String (typeParam). I know I am making a big assumption that there is only one generic parameter, but that's fine for this simple example.
What I'd like to know is, based on the above, how do I do something like this:
For Each item As typeParam In obj1
'do something with it here
Next
Or even something as simple as getting obj1.Count().
The method that iterates over your list can specify a generic type:
Public Sub Foo(Of T)(list As List(Of T))
For Each obj As T In list
..do something with obj..
Next
End Sub
So then you can call:
Dim list As New List(Of String)
Foo(Of String)(list)
This method makes the code look a little hairy, at least in VB.NET.
The same thing can be accomplished if you have the objects that are in the list implement a specific interface. That way you can populate the list with any object type as long as they implement the interface, the iteration method would only work on the common values between the object types.
If you know that obj is a Generic List. Then you're in luck.
Generic List implements IList and IEnumerable (both are non-generic). So you could cast to either of those interfaces and then For Each over them.
IList has a count property.
IList also has a Cast method. If you don't know the type to cast to, use object. This will give you an IEnumerable(Of object) that you can then start using Linq against.