VB.Net Alternative to C# Underscore (discard) - vb.net

In c# i can do:
_ = Bla();
Can I do that in VB.Net ?
I think the answer is no but I just wanted to make sure.

The underscore (_), as used in your example, is C#'s discard token. Unfortunately, there is (currently) nothing similar in VB. There is a discussion about adding a similar feature on the VB language design github page.
In your example, however, you can just omit assigning the result (both in C# and VB), i.e.
Bla(); // C#
Bla() ' VB
The "discard variable" is particularly useful for out parameters. In VB, you can just pass an arbitrary value instead of a variable to discard unused ByRef parameters. Let me give you an example:
The following two lines are invalid in C#:
var b = Int32.TryParse("3", 0); // won't compile
var b = Int32.TryParse("3", out 0); // won't compile
Starting with C# 7, you can use _ for that purpose:
var b = Int32.TryParse("3", out _); // compiles and discards the out parameter
This, however, is perfectly valid in VB, even with Option Strict On:
Dim b = Int32.TryParse("3", 0)
So, yes, it would be nice to make the fact that "I want to ignore the ByRef value" more explicit, but there is a simple workaround in VB.NET. Obviously, once VB.NET gets pattern matching or deconstructors, this workaround won't be enough.

Related

Multiple assignment in single doesn't work

I am a C# guy working in VB.net. I am used to do it
lblErrorMsg.Text = txtErrorMsg.Value = vDataRow.Item("error_msg")
but it doesn't work in VB.Net. It sets
lblErrorMsg.Text = "False" and txtErrorMsg.Value = "" instead of actual value of vDataRow.Item("error_msg").
What's going on here?
In VB.NET that doesn't work, but i also dont like it in C#. In VB the = operator has two different purposes:
assignment operator
comparison operator (equal to)
So you are assigning the result of the comparison(which is a Boolean) to the String variable.
So you have to use this readable approach:
txtErrorMsg.Value = vDataRow.Item("error_msg") ' doesn't compile with Option Strict On (see below)
lblErrorMsg.Text = txtErrorMsg.Value
But another thing is more important, you should always set Option Strict to On, especially if you're already used to it because you are using C#. You have set it to Off because vDataRow.Item("error_msg") returns Object not String and even your comparison-assignment assigns a Boolean instead of resulting in a compiler-error. Use this instead:
txtErrorMsg.Value = vDataRow.Field(Of String)("error_msg")
In VB.NET treats the single equals in the r-value as a comparison. Hence its not possible to chaining assignment in VB

Confusion about the Argument< T > and Variable< T > in .NET 4.0 Workflow Foundation

I am using Windows Workflow Foundation in .NET 4.0. Below is some syntax/semantic confusion I have.
I have 2 equivalent way to declare an Assign activity to assign a value to a workflow variable (varIsFreeShipping).
(1) Using XAML in the designer.
(2) Using code.
But in approach 2, the it seems I am creating a new OutArgument< Boolean > and assign value to it, not to the original Variable< Boolean> varIsFreeShipping. And OutArgument and Variable are totally different types.
So how could the value assigned to this new Argument finally reach the original Variable?
This pattern seems common in WF 4.0. Could anybody shed some light on this?
Thanks!
As a matter of fact, the second (2) method can be written just as:
Then = new Assign<bool>
{
To = varIsFreeShipping,
Value = true
}
This all works because OutArgument<T> can be initialized through a Variable<T> using an implicit operator.
In your first (1) assign, using the editor, that's what's happening behind the scene; the variable is being implicitly converted from Variable to OutArgument.
WF4 uses alot of implicit operators mainly on Activity<T> from/to Variable<T>, OutArgument<T> from/to Variable<T>, etc. If you look at it, they all represent a piece of data (already evaluated or not), that is located somewhere. It's exactly the same as in C#, for example:
public int SomeMethod(int a)
{
var b = a;
return a;
}
You can assign an argument to a variable, but you can also return that same variable as an out argument. That's what you're doing with that Assign<T> activity (using the variable varIsFreeShipping as the activity's out argument).
This answers your question?

Invoke anonymous methods

Is there any difference under the hood between line 4 and line 5?
Why can't VB.net handle Line 3?
What is the proper way to call the function?
Dim aFunc As New Tuple(Of Func(Of String))(Function() "Hello World")
Dim s As String
s = aFunc.Item1() 'does not compile
s = (aFunc.Item1)()
s = aFunc.Item1.Invoke()
This looks like a compiler bug to me, the parentheses should make it unambiguously a method call. Hard to state this for a fact however, parens are heavily overloaded in vb.net to mean many things. Clearly it is the tuple that makes the compiler fumble, it works fine without it. This came up in this week's StackExchange podcast with Eric Lippert btw, you might want to listen to it to get the laundry list of things it can mean.
You could post this to connect.microsoft.com to get the opinion of the language designers. The behavior is certainly unintuitive enough to call it a bug. The workarounds you found are good. Both generate the exact same code and add no overhead, something you can see by running ildasm.exe on your assembly.
aFunc.Item1 is a Function, so you can't assign it to a String. You appear to want:
Dim aFunc As New Tuple(Of Func(Of String))(Function() "Hello World")
Dim s As String
Dim f As Func(Of String) = aFunc.Item1
s = f.Invoke()
EDIT:
s = aFunc.Item1() accesses the property Item1. To invoke the function which that property refers to, you can use s = aFunc.Item1()(), which is equivalent to your line 4. At a guess, property access is stronger than function invocation (if those are the correct terms).

Write String.Join(Of T) in VB.Net

I have a simple code in C#:
Console.WriteLine(string.Join<char>("", ""));
And I can't convert it to VB.Net. Even reflector show me code in VB like:
Console.WriteLine(String.Join(Of Char)("", ""))
But it can't be compiled becouse I have an starge error:
Error 1 Expression expected.
It looks like VB.Net don't have this generic method at all.
Both project use Net Framework 4.
Why this error happened?
UPD:
I've create a custom class and copy Join(Of T) declaration to it:
Class string2
Public Shared Function Join(Of T)(ByVal separator As String, ByVal values As System.Collections.Generic.IEnumerable(Of T)) As String
Return "1"
End Function
End Class
Console.WriteLine(string2.Join(Of Char)("", ""))
It works
UPD2:
My compilation string, where you can see that I'm using Net4:
http://pastebin.com/TYgS3Ys3
Do you have a code element named String somewhere in your project?
Based on the answer you have added to this question (where you indicate that changing String to [String] appears to have solved the problem), I guessed that this may be the result of a naming collision.
I was able to duplicate the error you are seeing -- "Expression expected" -- by adding a module to my project called String and defining a (non-generic) Join method from within that module.
This may not be the specific scenario you find yourself in. But the fact that the code works for you with [String] is, to me, very compelling evidence of a simple namespace collision.
Based on the documentation for the "Expression expected" error, I'm guessing you haven't included the entire section of code where this error is appearing for you.
Do you have a lingering operator such as + or = somewhere?
(The VB.NET code you posted is indeed equivalent to the C# code above it and should compile no problem. This is why I suspect the real issue lies elsewhere.)
String.Join<T>(string, IEnumerable<T>) is useful with LINQ, for standard joins is better to use the String.Join(string, string()) overload.
In C#, "" as Char produces an empty Char (\0). Writing the same thing ("") in VB produces an empty string which is not the same as an empty char. In order to produce an empty character, you'll have to write New Char().
Your VB code therefore becomes:
Console.WriteLine(String.Join(Of Char)(New Char(), New Char()))
Edit
I just checked and it appears String.Join does not support the format you're specifying.
Instead, it goes as follows:
Join(separator As String, value As String()) As String
Your code should be as follows:
Console.WriteLine(String.Join("", New String() {""}))
String.Join(Of Char)(str1, str2) wasn't added til .net 4, it seems. That's why your custom class worked -- it had the declaration, but the String class in the framework you're actually using doesn't.
Check your settings and references to make sure you're targeting .net 4 all around -- cause that's the only thing that seems able at this point to stop the call from working.
Here the solution:
Console.WriteLine([String].Join(Of Char)("", ""))
Why this problem occurs only with generic method? I wish I know...

In VB6, how do I call a COM object requiring a pointer to an object?

I'm having trouble with a .NET Assembly that is com visible, and calling certain methods from VB6.
What I have found is that if the parameters are well defined types, (e.g. string), calls work fine. If they are higher level objects, it raises a runtime error '438' suggesting that the property or method is not present. I suspect that this is a question of having the correct signature on the call, but I can't see how to do this correctly.
I believe that I've done everything correct on the .NET side (ComVisible, public interfaces, etc. and even have it down to a simple enough case).
Looking at the output from the typelib viewer, I have the following:
dispinterface ISimple {
properties:
methods:
[id(0x60020000)]
void Add([in] ISimpleMember* member);
[id(0x60020001)]
ISimpleMember* Create();
};
OK. So I have 2 methods in my ISimple interface. One takes an ISimpleMember (Add), whilst the other, returns an ISimpleMember.
The corresponding code in VB looks like this:
Dim item As ISimpleMember
Dim simple As simple
Set item = New SimpleMember
item.S1 = "Hello"
item.S2 = "World"
Set simple = New simple
simple.Add (item) <---- This raised the run time error 438
Set item = simple.Create <---- This works fine, returning me an ISimpleMember
I've tried a couple of things:
1. Dim item as SimpleMember (makes no difference)
2. simple.Add(ObjPtr(item)) - Syntax error
3. simple.Add(ByRef item) - Syntax error
Basically, The run time error is the same as if I had
simple.AMethodThatIHaventWritten()
Also, If I browse References in the VB6 Environment, The Add method is well defined:
Sub Add(member As SimpleMember)
I've found the answer I believe. It was very simple:
When calling a SubRoutine, I shouldn't put the name in braces. the call should have been:
simple.add member
rather than
simple.add(member)
If I change it to a function (i.e. return a value rather than void) the braces are necessary
This seems to work
(Probably) The top 3 VB6 coding mistakes made by devs who now mainly code in C#, Javascript etc. Are:-
Placing ; at the end of lines. Its a syntax error very easily spotted and picked up the compiler.
Not placing Then on the other side of an If condition expression. Again its a syntax error.
Calling a method without retrieving a value and yet using ( ) to enclose the parameter list. With multiple parameters this is a syntax error and easily found. With only one parameter the use of ( ) is interpreted as an expression. Its the result of the ( ) expression which is passed as parameter. This causes problems when ByRef is expected by the callee.