Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Elegant way of reading a child property of an object

Say you are trying to read this property

var town = Staff.HomeAddress.Postcode.Town; 

Somewhere along the chain a null could exist. What would be the best way of reading Town?

I have been experimenting with a couple of extension methods...

public static T2 IfNotNull<T1, T2>(this T1 t, Func<T1, T2> fn) where T1 : class {     return t != null ? fn(t) : default(T2); }  var town = staff.HomeAddress.IfNotNull(x => x.Postcode.IfNotNull(y=> y.Town)); 

or

public static T2 TryGet<T1, T2>(this T1 t, Func<T1, T2> fn) where T1 : class { if (t != null) {     try     {         return fn(t);     }     catch{ } } return default(T2); }  var town = staff.TryGet(x=> x.HomeAddress.Postcode.Town); 

Obviously these are just abstracting away the logic and making the code (a little) more readable.

But is there a better/ more efficient way?

EDIT:

In my particular case the objects are being returned from a WCF service and I have no control over the architecture of those objects.

EDIT 2:

There is also this method:

public static class Nullify {     public static TR Get<TF, TR>(TF t, Func<TF, TR> f) where TF : class     {         return t != null ? f(t) : default(TR);     }      public static TR Get<T1, T2, TR>(T1 p1, Func<T1, T2> p2, Func<T2, TR> p3)         where T1 : class         where T2 : class     {         return Get(Get(p1, p2), p3);     }      /// <summary>     /// Simplifies null checking as for the pseudocode     ///     var r = Pharmacy?.GuildMembership?.State?.Name     /// can be written as     ///     var r = Nullify( Pharmacy, p => p.GuildMembership, g => g.State, s => s.Name );     /// </summary>     public static TR Get<T1, T2, T3, TR>(T1 p1, Func<T1, T2> p2, Func<T2, T3> p3, Func<T3, TR> p4)         where T1 : class         where T2 : class         where T3 : class     {         return Get(Get(Get(p1, p2), p3), p4);     } } 

from this article http://qualityofdata.com/2011/01/27/nullsafe-dereference-operator-in-c/

like image 1000
David Avatar asked Apr 21 '11 13:04

David


1 Answers

The best way would be to avoid violating the law of Demeter.

var town = Staff.GetTown(); 

And in Staff:

string GetTown() {     HomeAddress.GetTown(); } 

And in HomeAddress:

string GetTown() {     PostCode.GetTown(); } 

And in PostCode:

string GetTown() {     Town.GetTownName(); } 

Update:

Since you don't have control over this, you can use short circuit evaluation:

if(Staff != null     && Staff.HomeAddress != null    && Staff.HomeAddress.PostCode != null    && Staff.HomeAddress.PostCode.Town != null) {     var town = Staff.HomeAddress.Postcode.Town; } 
like image 75
Oded Avatar answered Sep 24 '22 03:09

Oded