The best way would be to avoid violating the law of Demeter.
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; }.
Oded: Agreed, but in this case it is out of my control. – Dve Apr 21 '11 at 13:23 The best way would change it to be Staff. Town – David Basarab Apr 21 '11 at 13:23 1 @Dve if it is out of your control than you can encapsulate Staff inside one of your objects.
– David Basarab Apr 21 '11 at 13:23 @Dve - Tiny detail that you have failed to mention in your question, my friend. How about adding it now? – Oded Apr 21 '11 at 13:24 @Oded: Apologies!
Have edited the post. – Dve Apr 21 '11 at 13:27.
Var town = "DefaultCity"; if (Staff! = null && Staff. HomeAddress!
= null && Staff.HomeAddress. Postcode! = null && Staff.HomeAddress.Postcode.
Town! = null) { town = Staff.HomeAddress.Postcode. Town; }.
– Dve Apr 21 '11 at 13:31 7 This might not win you any points for elegance/creativity in a comp sci classroom. But if I came across this code "in the wild", I would immediately know what it was doing and why. Sometimes simplicity/pragmatism is the best approach.
– mikemanne Apr 21 '11 at 13:33 Yep. Try/gets are more consuming in this case – Evgeny Gavrin Apr 21 '11 at 13:34 @mikemanne +1 no elegance at all, but understandable – Evgeny Gavrin Apr 21 '11 at 13:38 2 @Dve - it is much worse, as you are relying on an exception to be thrown (and if it gets thrown, it will be more expensive). – Oded Apr 21 '11 at 14:14.
I agree with Oded that this violates the Law of Demeter. I was intrigued by your question though, so I wrote up a a poor man's "Null-Safe Evaluate" extension-method with expression-trees, just for fun. This should give you compact syntax to express the desired semantics.
Please don't use this in production code. Usage: var town = Staff. NullSafeEvaluate(s => s.HomeAddress.Postcode.
Town); This will evaluate in succession: Staff Staff. HomeAddress Staff.HomeAddress. Postcode Staff.HomeAddress.Postcode.
Town (Caching and reusing the values of the intermediate expressions to produce the next one) If it encounters a null reference, it returns the default value of the type of Town. Otherwise, it returns the value of the full expression. (Not throughly tested, can be improved in terms of performance and doesn't support instance-methods.
POC only. ) public static TOutput NullSafeEvaluate (this TInput input, Expression selector) { if (selector == null) throw new ArgumentNullException("selector"); if (input == null) return default(TOutput); return EvaluateIterativelyOrDefault (input, GetSubExpressions(selector)); } private static T EvaluateIterativelyOrDefault (object rootObject, IEnumerable expressions) { object currentObject = rootObject; foreach (var sourceMemEx in expressions) { // Produce next "nested" member-expression. // Reuse the value of the last expression rather than // re-evaluating from scratch.
Var currentEx = Expression. MakeMemberAccess (Expression. Constant(currentObject), sourceMemEx.
Member); // Evaluate expression. Var method = Expression. Lambda(currentEx).Compile(); currentObject = method.DynamicInvoke(); // Expression evaluates to null, return default.
If (currentObject == null) return default(T); } // All ok. Return (T)currentObject; } private static IEnumerable GetSubExpressions (Expression selector) { var stack = new Stack(); var parameter = selector.Parameters.Single(); var currentSubEx = selector. Body; // Iterate through the nested expressions, "reversing" their order.
// Stop when we reach the "root", which must be the sole parameter. While (currentSubEx! = parameter) { var memEx = currentSubEx as MemberExpression; if (memEx!
= null) { // Valid member-expression, push. Stack. Push(memEx); currentSubEx = memEx.
Expression; } // It isn't a member-expression, it must be the parameter. Else if (currentSubEx! = parameter) { // No, it isn't.
Throw, don't support arbitrary expressions. Throw new ArgumentException ("Expression not of the expected form. ", "selector"); } } return stack; }.
2 This is very interesting! – Dve Apr 21 '11 at 15:45.
As per encapsulation, it is always the duty of a class to make proper validation (i.e. Null-checks) for it's fields (and properties) before returning them. So each object is responsible for its fields, you can choose to return null, empty string, or raise an exception and handle it one level up in the chain.
Trying to work around this is like trying to work around encapsulation.
If (and only if) it will be infrequent, I would use try { var town = staff.HomeAddress.Postcode. Town; // stuff to do if we could get the town } catch (NullReferenceException) { // stuff to do if there is a null along the way }.
Here a solution using null coalescing operators that I put together for fun (other answers are better). If you except this as the answer I'll have to hunt you down and uh, take your keyboard away! :-) Basically, if any object in Staff is null its default will be used instead.
// define a defaultModel var defaultModel = new { HomeAddress = new { PostCode = new { Town = "Default Town" } } }; // null coalesce through the chain setting defaults along the way. Var town = (((Staff? DefaultModel) .
HomeAddress? DefaultModel. HomeAddress) .
PostCode? DefaultModel.HomeAddress. PostCode) .
Town? DefaultModel.HomeAddress.PostCode. Town; Disclaimer, I'm a javascript guy and we javascripters know that accessing an object's properties can get expensive - so we tend to cache just above everything, which is what the code above accomplishes (each property is only looked up once).
With C#'s compilers and optimizers it probably isn't necessary to do it (some confirmation on this would be nice).
I came up with the same solution as Ani's some time ago, see this blog post for details. While elegant, it's very inefficient... var town = Staff. NullSafeEval(s => s.HomeAddress.Postcode.
Town, "(N/A)"); A better solution IMHO is the one suggested in this CodeProject article: string town = Staff. With(s => s. HomeAddress) .
With(a => a. Postcode) . With(p => p.
Town); The only thing I don't like with this solution is the name of the extension method, but it can easily be changed...
Another go: Declare a helper method bool HasNull(params object objects) { foreach (object o in objects) { if (o == null) return true; } return false; } Then use it like this: if (!HasNull(Staff, Staff. HomeAdress, Staff.HomeAddress. Postcode, Staff.HomeAddress.Postcode.
Town)) { town = Staff.HomeAddress.Postcode. Town; }.
If (Staff?Staff. HomeAdress?Staff.HomeAddress. Postcode?Staff.HomeAddress.Postcode.
Town! = null) { var town = Staff.HomeAddress.Postcode. Town }.
Pretty cool except for declaring town in the if. ;) – Trey Carroll Apr 21 '11 at 17:27 Staff? Staff.
HomeAddress has different types on both sides of the operator, so this usage won't compile. Additionally, if Staff is null, the? Operator will invoke Staff.
HomeAddress resulting in a null ref exception. – Juliet Apr 21 '11 at 21:28 Posted very late yesterday (it was, here in Thailand), and realized all the shortcomings later. So, no, it wouldn't work... – Peter Apr 22 '11 at 7:48.
I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.