Val Function and overload notice - vb.net

in the MSDN, this is the description of VAL() function:
This member is overloaded
What's overload property? why part of functions or methods in .NET have this property?

From MSDN:
In an OOP language such as Microsoft® Visual Basic® .NET, you are allowed to create methods in a class that have the same name but different argument lists. Visual Basic .NET can figure out which method to call during compile based on the parameter types that you pass. This technique is called overloading a method.
Example for VAL()
Public Overloads Function Val(ByVal InputStr As String) As Double
' -or-
Public Overloads Function Val(ByVal Expression As Object) As Double
' -or-
Public Overloads Function Val(ByVal Expression As Char) As Integer

Function overloading allows you to have 2 functions with the same name but with different arguments.
Eg:
DoSomething();
DoSomething(int arg1);

Related

How can I disambiguate '=' symbol in VB.NET, in a lambda function

I am using Dapper to query a flat list of items from a database, into a POCO class as follows:
Public Class Node
Public Property Name As String
Public Property ParentNodeName As String
Public Property Children As IEnumerable(Of Node)
End Class
I am trying to use the accepted answer to this question, in order to create a tree out of the flat list.
The only caveat is that I am using VB.NET.
I have tried it a straightforward port of the C# solution:
nodes.ForEach(Function(n) n.Children = nodes.Where(Function(ch) ch.ParentNodeName = n.Name).ToList)
but it does not compile with the error
Error BC30452 Operator '=' is not defined for types 'List(Of Node)' and 'List(Of Node)'.
The = symbol is interpreted as an equality operator, while I meant to use the assignment operator.
I have pasted the C# code into the telerik converter, and the converted code is:
Private Shared Function BuildTree(ByVal items As List(Of Category)) As IEnumerable(Of Category)
items.ForEach(Function(i) CSharpImpl.__Assign(i.Categories, items.Where(Function(ch) ch.ParentId = i.Id).ToList()))
Return items.Where(Function(i) i.ParentId Is Nothing).ToList()
End Function
Private Class CSharpImpl
<Obsolete("Please refactor calling code to use normal Visual Basic assignment")>
Shared Function __Assign(Of T)(ByRef target As T, value As T) As T
target = value
Return value
End Function
End Class
It uses an helper class to solve this issue, but suggests a refactor to avoid this.
Hence the questions:
Is there a general way to disambiguate equality = and assignment = in VB.NET, without resorting to an helper class and a specific function to assignement
In this specific case, is there a simple refactor I can use to get rid of the issue?
That's because of VB.Net distinction between functions and subroutines.
Instead of
nodes.ForEach(Function(n) n.Children = nodes.Where(Function(ch) ch.ParentNodeName = n.Name).ToList)
use
nodes.ForEach(Sub(n) n.Children = nodes.Where(Function(ch) ch.ParentNodeName = n.Name).ToList)
When you use Function, the lambda expression is expected to return a value; and in your case it looks like it wants to return a boolean.
But you want to use a lambda expression that does not return anything (in your case, you want an assignment), you have to use Sub.

Passing function as parameter in c# works but not in vb.net?

So I have the following line of code in c# to register AutoMapper with SimpleInjector:
container.Register(() => config.CreateMapper(container.GetInstance));
For context, config.CreateMapper() looks like this:
public IMapper CreateMapper(Func<Type, object> serviceCtor);
While container.GetInstance looks like this:
public object GetInstance(Type serviceType);
The first line of code I posted works in C# because config.CreateMapper takes in a function that takes a type of Type and returns a type of object. Exactly what container.GetInstance does.
When I try to do this same line in VB, as:
container.Register(Function() config.CreateMapper(container.GetInstance))
It gives an error Type arguments for 'Public Function Container.GetInstance(Of TService)()' cannot be inferred from the usage. Try specifying type arguments explicitly. It is giving this error because container.GetInstance has an overload that looks like this:
public TService GetInstance<TService>() where TService : class;
Why does the VB try to use the wrong overload of GetInstance and how can I force it to use the correct one?
Use AddressOf for getting function reference.
container.Register(Function() config.CreateMapper(AddressOf container.GetInstance))
In C# function with parenthesis executes it, function without parenthesis will return reference to the function.
In VB.NET parenthesis in function are optional - function will be executed anyway. So for referencing a function you should use AddressOf operator.
AddressOf Operator
Use the AddressOf keyword before the function parameter to define this as Parameter as function pointer.
AddressOf ist the same as # keyword in C#. The keyword is implicit used in your c# sample.

VB.NET unable to differentiate between overloaded functions

Current version of MVVM Light has a helper function named Set in ObservableObject class that an inheriting ViewModel class can call to both change property value and raise change notification in one call. Together with the new NameOf operator, this makes the boilerplate code of properties much smaller.
The problem however is that the Set function is overloaded and out of the 3 overloads, the following 2 overloads make VB.NET angry:
Protected Function [Set](Of T)(propertyName As String, ByRef field As T, newValue As T) As Boolean
Protected Function [Set](Of T)(ByRef field As T, newValue As T, <CallerMemberName> Optional propertyName As String = Nothing) As Boolean
Now if you have a String type property, VB.NET cannot differentiate as to which overload we are calling.
Overload resolution failed because no accessible '[Set]' is most specific for these arguments:
'Protected Overloads Function [Set](Of String)(propertyName As String, ByRef field As String, newValue As String) As Boolean': Not most specific.
'Protected Overloads Function [Set](Of String)(ByRef field As String, newValue As String, [propertyName As String = Nothing]) As Boolean': Not most specific.
Note that C# can handle this situation easily, by using ref keyword. Also that even though the current situation is related to MVVM Light, the problem itself is generic. I have tried to use named parameters too, but that doesn't help either. Any hints on how this could be solved?
Here again after almost a year. I just found a little workaround that would work in most cases. Instead of calling one of the overloads mentioned in the question, use the third overload:
Protected Function [Set](Of T)(ByRef field As T, newValue As T, <CallerMemberName> Optional propertyName As String = Nothing) As Boolean
The third parameter of this overload is optional and if you skip it in the call, it will use CallerMemberName to assign it a value. Since Set is almost always called from within the property, this approach should work nicely. No other overload takes two parameters, so compiler can resolve it correctly.

Return an inherited type from a method

Suppose I have the following classes defined:
Public Class BaseClass
...
End Class
Public Class DerivedClass
Inherits BaseClass
... Extra Fields, methods, etc ...
End Class
And then, in my code, I have a function with a signature of:
Public Function DoSomething(...) As List(Of BaseClass)
And when I try and return an object of type List(Of DerivedClass) from it, I get the error:
Value of type 'System.Collections.Generic.List(Of BaseClass)' cannot be converted to 'System.Collections.Generic.List(Of DerivedClass)'
I know not all the extra fields of the DerivedClass will be filled, but it would give me what I needed.
Is there a way to do this, or is this just considered bad programming practice? And, if so, what would be the right way to do this?
Have a look at this:
http://msdn.microsoft.com/en-us/library/dd799517(v=vs.110).aspx
Understanding Covariance and Contravariance will clear things up a bit :)
Covariance
Enables you to use a more specific type than originally specified.
You can assign an instance of IEnumerable (IEnumerable(Of Derived) in Visual Basic) to a variable of type IEnumerable.
Example:
IEnumerable<Derived> d = new List<Derived>();
IEnumerable<Base> b = d;
Contravariance
Enables you to use a more generic (less derived) type than originally specified.
You can assign an instance of IEnumerable (IEnumerable(Of Base) in Visual Basic) to a variable of type IEnumerable.
Example:
Action<Base> b = (target) => { Console.WriteLine(target.GetType().Name); };
Action<Derived> d = b;
d(new Derived());
Invariance
Means that you can use only the type originally specified; so an invariant generic type parameter is neither covariant nor contravariant. You cannot assign an instance of IEnumerable (IEnumerable(Of Base) in Visual Basic) to a variable of type IEnumerable or vice versa.

VB.NET Using System.Threading.Volatile.Write on Enum var types

I am in need of performing a volatile write on a variable that is an Enum type derived from Byte, but I am stucked.
This is my (example) code:
Public Class MyOwnClass
Friend Enum MyEnum As Byte
Val1
Val2
End Enum
Private MyEnumVar As MyEnum = MyEnum.Val1
Friend Sub SetMyEnumVar(ByVal value As MyEnum)
System.Threading.Volatile.Write(MyEnumVar, value) 'Error!
End Sub
End Class
Since Threading.Volatile.Write is not provided with a signature with those arguments I get this error
Error 1 Overload resolution failed because no accessible Write can be called without a narrowing conversion:
With the list of all the overloads of the method.
CTyping the first argument is not working, because CType returns a casted value of course not with the same reference as MyEnumVar where the method gets the first parameter abviously ByRef instead.
CObject that would return a reference is also not viable because the method also hasn't got the overload for an object type other than Write(Of T)(T, T) where Tmust be a class type.
So how can I accomplish my purpose?
Thanks.
You can use the Write(Of T) overload where T is the type of Enum.
System.Threading.Volatile.Write(Of [Enum])(MyEnumVar, value)