Multiple assignment in single doesn't work - vb.net

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

Related

VB.NET + LINQ: Save in a single class attribute the result of querying two columns from different tables

I have two tables: Estructura (with two fields I want: descripcion_morologica and interpretacion) and estrato (with two fields I want: descripcion_larga and interpretacion_explic). On the other side I hace a class in VS with the attributes descripcion and interpretacion. Both tables have a common field called id_excavacion, which I pass to the method as a parameter.
What I'm trying to achieve is to make a query which saves in the "descripcion" attribute the results of t1.descripcion_morfologica and t2.descripcion_larga and also saves in "interpretacion" the results of t1.interpretacion and t2.interpretacion_explic.
So far, I've tried like this:
'GET: api/Excavacions/ListadoUE/5
<Route("api/Excavacions/ListadoUE/{idExcavacion}")>
Function GetListadoUEs(ByVal idExcavacion As Integer) As IQueryable(Of ListadoUEDto)
Dim listado =
From estru In db.Estructura
Join estra In db.Estrato On estra.id_excavacion Equals estru.id_excavacion
Where estru.id_excavacion = idExcavacion
Select New ListadoUEDto With {
.Descripcion = estru.descripcion_morfologica And estra.descripcion_larga,
.Interpretacion = estru.interpretacion And estra.interpretacion_explic
}
End Function
But I only get null, despite the id I pass actually exists.
Thanks a lot in advance!!
You should almost certainly not be using And there. That is a Boolean operator, for combining True and False values. As is always the case, if you want to concatenate Strings then you use &, which is the string concatenation operator.
You should have Option Strict On and then the compiler would have warned you that you were doing something that doesn't make sense. You should turn it On in the project properties and also in the VS options, so it is On by default for future projects. That will force you to put more thought into what data types you use and, therefore, make you write better code.

VB.Net Alternative to C# Underscore (discard)

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.

Setting a variable to null value in inline if statement

I'm trying to use the following code to check for a DBNull and set the variable to nothing if it is, or a short if it isn't. The problem is it is failing to set the variable to Nothing and sets it to a 0 instead. Anybody know why?
variable = If(currentRow.Item("variable") Is DBNull.Value,
Nothing, CShort(currentRow.Item("variable")))
If variable is declared As Short? then the code works with a slight tweak: you need to cast either operand of If to the target type first:
variable = If(condition, CType(Nothing, Short?), CShort(…))
(You could also have cast the third operand instead, or both.)
This cast is necessary because of how If deduces types: if the two result types mismatch, a common type is deduced which is the closest parent type, i.e. a type from which both inherit. However, with Nothing, new rules come into play because as far as VB is concerned, Nothing is already a valid Short – a default-initialised one (see old answer below for explanation). So VB doesn’t try any type coercion, it simply uses Short as the return value.
Old answer below, assuming that OP had declared variable As Short:
You cannot set value types to Nothing. If you assign Nothing to a value type then it will be set to its type’s default value instead – which is 0 for Short.
You can test this easily:
Dim s as Short = Nothing
Console.WriteLine(s)
Setting a value type to Nothing is the same as invoking its default constructor (New Short()) or declaring a new variable of that type without initialising it. The corresponding operation in C# would be to assign default(T) (short s = default(short)).
If you want to represent null value types, you have to use nullable types:
Dim s as Short? = Nothing
Now s is of type Nullable<Short> (Short? is a shortcut of that) and can be assigned a proper Nothing.

VB.Net Linq to Entities Null Comparison - 'Is Nothing' or '= Nothing'?

We have several projects in VB.Net, using .Net Framework 4 and Linq to Entities for many of our SQL queries. Moving to EF is a new shift for us (been using it for about 4-6 months) and has the backing of upper management because we can code so much faster. We still use a lot of stored procs, but we even execute those through Linq to Entities as well.
I'm hoping to clear some confusion up and I can't find a direct answer that makes sense. We have some queries where we want records where a specific field has a NULL value. These are simple select queries, no aggregates or left joins, etc. Microsoft recommends the query look something like this MSDN Link:
dim query = from a in MyContext.MyTables
Where a.MyField = Nothing
Select a
I have several projects where I do exactly this and it works great, no warnings in the IDE. Recently a new project was created by another developer and when he did his null check like above, we all get this warning in the IDE:
Warning 1 This expression will always evaluate to Nothing (due to null propagation from the equals operator). To check if the value is null consider using 'Is Nothing'.
Comparing the projects, option explicit and option strict are on for each one. If we ignore the warning, we get the exact record set we are looking for when the app runs. The warning goes away if I change the = sign to IS. But why did this warning appear in one project and not others? It's confusing when even on MSDN there are examples using the equals operator.
Generated column should be a Nullable(Of T)
So you can check if that field has value or not like this:
dim query = from a in MyContext.MyTables
Where Not a.MyField.HasValue
Select a
I believe what you're seeing here is that MyField is a Nullable(Of T) type. Likely a primitive Integer, Single, etc ...
The reason you're seeing this warning is because the compiler promotes the normal equality operator for the primitive type to the Nullable(Of T) version. It essentially executes the following
Dim myField As Integer? = a.MyField
Dim other As Integer? = Nothing
If myField = other Then
...
End If
The issue though is that when Integer? has the value Nothing it won't compare equal to anything. Hence the above Where clause will always return False. The compiler is attempting to warn you about this problematic corner of Nullable(Of T) and push you to a Is Nothing check which will determine if a.MyField has a non-null value.
This blog article has a very detailed explanation of why this warning is being generated and all of the mechanics behind it. The article is written for C# but the basic premise is applicable to VB.Net as well.
http://blogs.msdn.com/b/abhinaba/archive/2005/12/14/503533.aspx
At least in LINQ to objects you can use this instead:
Nullable(Of Integer).Equals(a, b)
This works fine with both, either or none of the two values being Nothing.

Is there a conditional ternary operator in VB.NET?

In Perl (and other languages) a conditional ternary operator can be expressed like this:
my $foo = $bar == $buz ? $cat : $dog;
Is there a similar operator in VB.NET?
Depends upon the version. The If operator in VB.NET 2008 is a ternary operator (as well as a null coalescence operator). This was just introduced, prior to 2008 this was not available. Here's some more info: Visual Basic If announcement
Example:
Dim foo as String = If(bar = buz, cat, dog)
[EDIT]
Prior to 2008 it was IIf, which worked almost identically to the If operator described Above.
Example:
Dim foo as String = IIf(bar = buz, cat, dog)
iif has always been available in VB, even in VB6.
Dim foo as String = iif(bar = buz, cat, dog)
It is not a true operator, as such, but a function in the Microsoft.VisualBasic namespace.
If() is the closest equivalent, but beware of implicit conversions going on if you have set Option Strict off.
For example, if you're not careful you may be tempted to try something like:
Dim foo As Integer? = If(someTrueExpression, Nothing, 2)
Will give foo a value of 0!
I think the ? operator equivalent in C# would instead fail compilation.
Just for the record, here is the difference between If and IIf:
IIf(condition, true-part, false-part):
This is the old VB6/VBA Function
The function always returns an Object type, so if you want to use the methods or properties of the chosen object, you have to re-cast it with DirectCast or CType or the Convert.* Functions to its original type
Because of this, if true-part and false-part are of different types there is no matter, the result is just an object anyway
If(condition, true-part, false-part):
This is the new VB.NET Function
The result type is the type of the chosen part, true-part or false-part
This doesn't work, if Strict Mode is switched on and the two parts are of different types. In Strict Mode they have to be of the same type, otherwise you will get an Exception
If you really need to have two parts of different types, switch off Strict Mode (or use IIf)
I didn't try so far if Strict Mode allows objects of different type but inherited from the same base or implementing the same Interface. The Microsoft documentation isn't quite helpful about this issue. Maybe somebody here knows it.
If(<expression>, <expressionIfNothing>)
If <expression> evaluates to a reference or Nullable value that is not Nothing, the function returns that value. Otherwise, it calculates and returns <expressionIfNothing> (Intellisense)
This is useful for checking that a particular value exists, and if not replacing it.
Example:
If(cat, dog)
Here, if the cat is not null, it will return cat. If it is null, it will return dog. Most of the time you will be using a ternary operator for this scenario. However, if you do not want to return the value you are testing you will have to use this instead:
If(condition, cat(true), dog(false))