VB If statement in LINQ query - vb.net

I'm converting an old timed script from VB to C# and I need help with understanding what an If statement's purpose is.
The code I need help with is:
... And If(cp.JobTitle, String.Empty) = String.Empty And ...
This is part of a SQL query and the cp.JobTitle in the database is nullable string field.
Any help is appreciated!

No, that is not part of a SQL query. Perhaps it's part of a LINQ query or some code that constructs a SQL query but there's nothing to do with SQL there.
Anyway, that VB code is using the If operator with two operands. The equivalent of this VB:
If(cp.JobTitle, String.Empty) = String.Empty
is this C#:
(cp.JobTitle ?? string.Empty) == string.Empty
It's saying to use cp.JobTitle unless it's Nothing, in which case use String.Empty. A better way to write functionally equivalent VB would be this:
String.IsNullOrEmpty(cp.JobTitle)
I hope the equivalent C# to that is obvious.
By the way, that VB code really ought to be using AndAlso rather than And. If you would use && in C# rather than &, which pretty much everyone would, then you should be using AndAlso in VB rather than And. In both cases, you should only use the other if you explicitly don't want short-circuiting.

Related

Why And operator in vb.net

I always use AndAlso while checking multiple conditions as it doesn't evaluate right side unless left one is true. I don't see any situation where someone would like to evaluate right side even if left one fails. If it was needed then why they didn't include same in C#.
Update:
As accepted answer pointed out that it exists because it is used for bitwise operation, that fine enough but I still think they would have overloaded And operator to serve both purposes and just not created AndAlso. If anyone can pour some light on it, this question is still open :)
They included the same in C#. In C# you can use & (And) or && (AndAlso).
There's no real use case i can imagine for the not short-circuit operator when comparing booleans, but And can be used with numeric values, and it then does a bitwise comparison. That's why it exists. But when comparing boolean types, you'll always be using the short-circuit version.
And is also a bit operator. Here is an example showing a mix of And an AndAlso.
Dim foo? As Integer = 5
If foo.HasValue AndAlso (foo And 1) = 1 AndAlso (foo And 4) = 4 Then
Stop
End If

Is it efficient to use LINQ to parse strings?

I've been using LINQ so much in the last couple of weeks that when I had to write a one line function to remove < and > from a string, I found that I had written it as a LINQ query:
Public Function StripLTGT(text As String) As String
Return String.Join("", (From i As Char In text.ToCharArray Where i <> "<"c Where i <> ">"c).ToArray)
End Function
My question is, is it better to do it with LINQ as above or with StringBuilder as I've always done, as below:
Public Function StripLTGT(text As String) As String
Dim a As New StringBuilder(text)
a = a.Replace("<", "")
a = a.Replace(">", "")
Return a.ToString
End Function
Both work, the second one is easier to read, but the first one is designed for executing queries against arrays and other enumerables.
Regex.Replace("[<>]", "")
Is much more straightforward.
Or:
myString = myString.Replace("<", "").Replace(">", "")
Whether or not option A, B or C is faster than the others is hard to say because option A may be better on small strings while option B may be better on long strings, etc.
Either one should really be fine in terms of functionality. The first one is not efficient as is. The ToArray call is doing far more work than necessary (if you're on .NET 4.0, it is not needed anyway), and the ToCharArray call is not needed. Basically the characters in the input string are being iterated a lot more than they need to be, and extra arrays are allocated superfluously.
I wouldn't say this particularly matters; but you asked about efficiency, so that's why I mention it.
The second one seems fine to me. Note that if you wanted to go the one-line route, you could still do so with a StringBuilder and I think still have something more concise than the LINQ version (though I haven't counted characters). Whether or not this even outperforms the more direct String.Replace option is kind of unclear to me, though:
' StringBuilder.Replace version:
Return New StringBuilder(text).Replace("<", "").Replace(">", "").ToString()
' String.Replace version:
Return text.Replace("<", "").Replace(">", "")

How to convert Boolean type into "ON" "OFF" using String.Format

Is there are any way to convert Boolean type into "ON"/"OFF" using string formatter, like:
Dim inpValue as Boolean
Dim outValue = String.Format("0:ON;OFF", inpValue)
' should show OFF as output
without code or IFormatProvider?
What is wrong with:
Dim inpValue as Boolean
Dim outValue = If(inpValue, "ON", "OFF")
Here's a crazy trick from another question but it's completely unreadable. I strongly advise you not to do this! If you are of nervous disposition, stop reading now.
String.Format("{0:ON;ON;OFF}", CDbl(inpValue))
This converts the Boolean to -1 or 0 and then uses a custom numeric format.
This should help you:
http://www.developmentnow.com/g/38_2004_4_0_0_238356/iformatprovider-for-boolean.htm
There isn't any built-in support that I am aware of. However, depending on how much control you have, you can create your own format provider (IFormatProvider). Here is a link to a discussion on this: bool format provider.
You can't do this using String.Format (without implementing IFormatProvider which seems like a overkill for your purposes), but you can do it in one line using IIf:
IIf(inpValue, outValue=True, outValue=False)
Personally, I recommend using an If/Else statement instead of IIf, as IIf is not intuitive for some programmers coming from other languages.
c# - not the most elegant but effective:
string outValue = inpValue.ToString().Replace("False", "OFF").Replace("True", "ON");

Issue with DBNull when using LINQ to DataSet

I've got the following LINQ Statement:
Dim PSNum As Integer = 66
Dim InvSeq = (From invRecord In InvSeqDataSet.RptInvSeqDT.AsQueryable() _
Where IIf(invRecord.IsPack_NumNull(), False, invRecord.Pack_Num = PSNum) _
Select New With _
{.Inv = invRecord.Invoice_Num, .Seq = invRecord.Inv_Seq}).FirstOrDefault()
invRecord.Pack_Num is a field of type Integer. This means that when I try to access it, if it is DBNull I get a StronglyTypedException. The above code throws this exception. If, however, I remove the "invRecord.Pack_Num = PSNum" and in its place put something like "True", the code works fine.
So I guess my question is, why is that that invRecord.IsPack_NumNull() returns False when the value is in fact DBNull and what can I use as a conditional instead? I've been beating my head against the wall for a while now and I can't find a solution to this problem.
In VB.NET, IIf() evaluates every one of its arguments since it's a function, not a language statement. So inv.Record.Pack_Num = PSNum will always be evaluated.
You can use If() instead of IIf() (same syntax) which uses short-circuiting evaluation so everything will work as expected.
On a side node, be careful with And and Or which have the same behavior. Use AndAlso and OrElse instead if you need short-circuiting evaluation.

dynamically varied number of conditions in the 'where' statement using LINQ

I'm working on my first project using LINQ (in mvc), so there is probably something very simple that I missed. However, a day of searching and experimenting has not turned up anything that works, hence the post.
I'm trying to write a LINQ query (Linq to SQL) that will contain a multiple number of conditions in the where statement separated by an OR or an AND. We don't know how many conditions are going to be in the query until runtime. This is for a search filter control, where the user can select multiple criteria to filter by.
select * from table
where table.col = 1
OR table.col = 2
OR table.col = 7
.... 'number of other conditions
Before I would just construct the SQL query as a string while looping over all conditions. However, it seems like there should be a nice way of doing this in LINQ.
I have tried looking using expression trees, but they seem a bit over my head for the moment. Another idea was to execute a lambda function inside the where statement, like so:
For Each value In values
matchingRows = matchingRows.Where(Function(row) row.col = value)
However, this only works for AND conditions. How do I do ORs?
I would use PredicateBuilder for this. It makes dynamic WHERE clauses very easy.
AND is easy - you can just call Where in a loop. OR is much trickier. You mention SQL, so I'm assuming this is something like LINQ-to-SQL, in which case one way I've found to do this involves building custom Expression trees at runtime - like so (the example is C#, but let me know if you need help translating it to VB; my VB isn't fantastic any more, so I'll let you try first... you can probably read C# better than I can write VB).
Unfortunately, this won't work with EF in 3.5SP1 (due to the Expression.Invoke), but I believe this is fixed in 4.0.
Something like this should work (forgive my VB):
Expression(Of Func(Of Something, Boolean)) filter = Nothing
ParameterExpression rowParam = Expression.Parameter("row", CType(Something))
For Each value In values
filterPart = Expression.Equal( _
Expression.Property(rowParam, "col"), _
Expression.Constant(value)))
If filter Is Nothing Then
filter = filterPart
Else
filter = Expression.OrElse(filter, filterPart)
End If
Next
If newPredicate IsNot Nothing Then
matchingRows = matchingRows.Where( _
Expression.Lambda(Of Func(Of SomeType, Boolean))(filter, rowParam))
End If
No guarantees, however, my VB is a little rusty :-)
But PredicateBuilder might be a better solution if you want to do more complicated stuff than just Ands and Ors.