3

I'm looking for a 'safe' dot notation in VB.net. Does such a thing exist - in VB.NET or any language? What I want to be able to do is, when using non-nullable legacy objects, to solve a problem like:

"if there as a plan, if there is a case, if it has a person, that person's spouse, else, nothing (VBSpeak for Null)."

and avoid doing this:

Dim Spouse as Person = Nothing
if Case.Plan isnot nothing then
    if Case.Plan.Person isnot Nothing
        Spouse = Case.Plan.Person.Spouse
    end if
end if

and do this:

Dim Spouse as Person = Case~Plan~Person~Spouse

Where '~' is my sought 'safe' dot notation, which immeditely returns a null upon encountering the first null object instead of throwing an exception?

More common for this problem of course:

dim MyVar as string = XMLDoc.DocumentElement.SelectSingleNode("Name").InnerText

and wanting Nothing instead of an exception when Name doesn't exist.

Edit:

Is there a way to solve this problem using LINQ for objects or LINQ for XML?

Peter Duniho
  • 68,759
  • 7
  • 102
  • 136
FastAl
  • 6,194
  • 2
  • 36
  • 60
  • While I'd settle for LINQ queries if such a thing doesn't exist, I'm more curious than anything else. And some huge old programs are still waiting upgrade from .Net2.0 (not my choice:-) For newer programs we try to use other solutions. – FastAl Mar 21 '11 at 14:26
  • see also http://stackoverflow.com/questions/1196031/evil-use-of-maybe-monad-and-extension-methods-in-c and other search results for "safe dereferencing operator" – AakashM Mar 21 '11 at 14:28
  • @AakashM - AHH 'safe dereferencing operator' I _knew_ there was a right name for it that my weak google-fu was missing! – FastAl Mar 21 '11 at 14:32

4 Answers4

3

VB.NET 14 introduced the null-conditional operator to address this. This operator is also short-circuiting.

Dim Spouse as Person = Case?.Plan?.Person?.Spouse

Used to test for null before performing a member access (?.) or index (?[) operation. These operators help you write less code to handle null checks, especially for descending into data structures.

The same thing works in C#:

Person spouse = Case?.Plan?.Person?.Spouse;
Peter Duniho
  • 68,759
  • 7
  • 102
  • 136
Saragis
  • 1,782
  • 6
  • 21
  • 30
1

I've generally used extension methods for this sort of thing, very similar to what the thread that AakashM pointed to. A good example of this is string LENGTH. Since the LENGTH function is an instance method, if you invoke it on a null string object, you'll throw.

But code up an extension method LEN on the string class that tests for null and you can have it return 0 (I happen to consider null strings 0 length virtually all the time, but that's a topic for another thread.)

Using that same logic, you could implement an IsNotNull, or maybe an IsValid. the main problem will be "stopping" the continued property resolution (from, say, Case to Plan)

the methods on the above mentioned thread use Lambdas, which yields a pretty unwieldy syntax if you ask me. I suspect it'd be possible to, if the IsNotNull test yields a null, to return a Proxy object that stands in for the null, and would simply resolve anything method call you make on it to a null as well. But that would require a dynamic proxy which is messy in and of itself.

DarinH
  • 4,868
  • 2
  • 22
  • 32
  • __Totally agree__. I use Len, Mid, Left, and all the old VB string functions even though they are _obnoxiously_ 1-based, because of the cost of extra protection code or worse yet bugs from the string object versions. They have other nice protections. Really for `MsgBox(Mid("", 2, 5))` it would be 'proper' to throw an exception, as string.substring does - unfortunately in real programming you want `""` 99% of the time - which is what Mid returns!!! – FastAl Mar 21 '11 at 14:52
  • Yeah, the one base is a bit of a drag in .net since everything else is 0 base. Using the extension methods, though, you can make those functions 0 or 1 based, as you prefer. I WISH there was a way for an extension method to override an instance method. then I could Override the .net LENGTH method with one that works more like the way I need it to work, but alas, that's not possible. – DarinH Mar 21 '11 at 16:44
1

There is no null-safe dot notation in VB versions prior to 14 (Visual Studio 2015).

A nicer way of dealing with possible null values, without having too many ifs, is to use AndAlso (short-circuiting And):

If Case.Plan IsNot Nothing _
AndAlso Case.Plan.Person IsNot Nothing _
AndAlso Case.Plan.Person.Name = "Something" Then
    'Do something here
End If

Another options is to use the Null Object Pattern. But that would only be possible with your own data types and would require some changes in your code.

Edit:

To answer your question about LINQ, it can't help you with this. LINQ's goal is to help you query sets of data (lists, arrays, etc.). If you try to query your data with LINQ you'll have the same problem if one of your objects is null.

Meta-Knight
  • 17,626
  • 1
  • 48
  • 58
  • I should clarify the point here that the unfortunate answer to both my questions is NO and NO. Answer marked here because I already favor using the above 2 of his 3 poinst to solve this problem, and, the 3rd point provides the answer to my LINQ question (unfortunately 'NO') of which I had no clue one way or another as a total linq n00b. – FastAl Mar 31 '11 at 13:20
1

That's about it for the VB.NET syntax, it doesn't have anything resembling the null coalescing operator like C#'s ?? operator. The Iif() function can write more compact If statements but they rarely work for null references since both arguments are evaluated.

In general, try to favor null references as a debugging aid. They throw a nice exception when some other code you didn't write is calling yours but messed up something like initialization. Silently propagating programming bugs leads to hard to diagnose failure. Like a NullReferenceException that's far removed from the cause. Or worse, bad data. You could perhaps address your scenario with a NotAPlan and a NoSpouse object, objects that solely exists to avoid null reference exceptions and logically mean "no plan assigned, no spouse defined". A reference that can be null is otherwise nothing more than a reference + a boolean. Don't skip the bool.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536