0

I am trying to get a string of BranchCode from an array of UserBranches(). For a specific user the list is nothing, therefore is causing an exception:

System.ArgumentNullException: 'Value cannot be null.
Parameter name: source'

I am using an IIF statement, but obviously does not help:

Dim sMatchedBranches = IIf(Not IsNothing(oUser.UserBranches),
                           oUser.UserBranches.Select(Function(z) String.Format("{0} - BranchCode", z.BranchCode)), "")

I have also used oUser.UserBranches.Any, but still the same exception. Any ideas?

** To the duplicate recommendation, it's actually not since the question combines both the IIF and also an empty array with lambda expressions.

alwaysVBNET
  • 3,150
  • 8
  • 32
  • 65
  • 1
    Use `If()` instead of `IIf()`. – rskar Jun 02 '18 at 15:43
  • 2
    "Any ideas?" - Yes, select the ""References Tab" after clicking the Project Menu->"Project Name" Properties. Then under "Imported namespaces", uncheck "Microsoft.VisualBasic". This will make it harder for you to use the functions (like `IIf`) meant to make VB6 programmers comfortable in VB.Net and instead use `If` or write a standard `If-Then` block. – TnTinMn Jun 02 '18 at 15:45
  • What version of VB are you using? If it's VB 14 or later, there is also the question mark operator (see https://visualstudiomagazine.com/Blogs/Tool-Tracker/2015/05/C-Sharp-VB-14-Null-Nothing.aspx). Also, `If()` has a two-parameter version. And there's `$""` (string interpolation). So this might work: `Dim sMatchedBranches = If(oUser.UserBranches?.Select(Function(z) $"{z.BranchCode} - BranchCode"), "")` – rskar Jun 02 '18 at 16:02
  • @rskar Nice answer. Please post it as answer and I will accept it. – alwaysVBNET Jun 02 '18 at 16:10
  • 1
    @alwaysVBNET - glad that helped! I'll post a very detailed answer for the benefit of future viewers. – rskar Jun 02 '18 at 16:22
  • Possible duplicate of [Using VB.NET IIF I get NullReferenceException](https://stackoverflow.com/questions/428959/using-vb-net-iif-i-get-nullreferenceexception) – TnTinMn Jun 02 '18 at 16:42
  • @TnTinMn It's not. The focus of the question is performing lamda on an empty list, not the IIF statement. – alwaysVBNET Jun 02 '18 at 17:37

1 Answers1

3

First, I would reiterate what @TnTinMn has said: Try to wean off Microsoft.VisualBasic. It's OK to pick-and-choose whatever's useful there - in which case be very thoughtful and intentional (e.g. even C#'ers like InputBox a lot! - What is the C# version of VB.net's InputDialog?). However, VB today has so many nicer and better ways of getting things done.

The major flaw of ye olde IIf() is that it is just some function, which means every parameter gets executed no matter the condition. That makes it barely useful, even in VB6/VBA, because you just can't avoid any run-time-error/exception that you know is going to happen per the condition. If() on the other hand is an actual operator, and it delivers exactly what everyone wants - a way to carefully prune what gets executed in an expression without having to write a specialized function.

So the easy answer is just to replace IIf() with If() and be pretty much done with it:

Dim sMatchedBranches = If(Not IsNothing(oUser.UserBranches),
                       oUser.UserBranches.Select(Function(z) String.Format("{0} - BranchCode", z.BranchCode)), "")

And one might feel that's good enough. But there's three other tricks in VB to make things nicer yet.

The first is the ? operator. This is a handy way to say something like If(oUser.UserBranches Is Nothing, Nothing, oUser.UserBranches.Select(Function(z) String.Format("{0} - BranchCode", z.BranchCode))), except with ? it's now like this:

oUser.UserBranches?.Select(Function(z) String.Format("{0} - BranchCode", z.BranchCode))

The second trick is string interpolation, in the format of $"{myVar}". Instead of String.Format("{0} - BranchCode", z.BranchCode), it can now be:

$"{z.BranchCode} - BranchCode"

The third trick is about If(): If you give it two parameters, it will give a very handy way of dealing with Nothing. If(x,y) means if x is not Nothing, return x, otherwise return y. (If(x,y) means the same as x ?? y in C#.)

Putting it all together:

Dim sMatchedBranches = If(oUser.UserBranches?.Select(Function(z) $"{z.BranchCode} - BranchCode"), "")
rskar
  • 4,607
  • 25
  • 21
  • My goal was to get the branch codes as a string. By checking again now the code I get an error. Any ideas? Dim sMatchedBranches As String = If(oUser.UserBranches?.Select(Function(z) $"{z.BranchCode} - BranchCode"), "") – alwaysVBNET Jun 03 '18 at 13:28
  • Ok, I did this: Dim sMatchedBranches As String = String.Join(",", oUser.UserBranches?.Select(Function(z) $"{z.BranchCode} - BranchCode")) which works – alwaysVBNET Jun 03 '18 at 14:08
  • 1
    So, the goal is a comma-separated list of items? `String.Join` is fine for that, so what you have looks OK to me. But you probably still need to use `If(x,y)` in case oUser.UserBranches is Nothing. – rskar Jun 03 '18 at 14:12
  • now that I have put back the if(x,y) instead of CSV I get this: sMatchedBranches = "System.Linq.Enumerable+WhereSelectArrayIterator`2[TestBlcWS_winnapp.sr.Branches,System.String]" – alwaysVBNET Jun 03 '18 at 14:19
  • 1
    Try this (warning, I'm flying blind here): `Dim sMatchedBranches = String.Join(",", If(oUser.UserBranches?.Select(Function(z) $"{z.BranchCode} - BranchCode"), {""}))` I'm hoping to nudge String.Join towards where its second parameter is something IEnumerable. – rskar Jun 03 '18 at 14:24
  • 1
    Cool! I hope this is the real answer for you. – rskar Jun 03 '18 at 14:29