Consider this simple c# example:
var person = new Person {Name = "Fred", MailingAddress=null };
var result = String.Format("{0} lives at {1}",person.Name, person.MailingAddress.Street);
clearly this will throw a NullReferenceException because the MailingAddress proptery is null.
I could rewrite the second line as:
var result = String.Format("{0} lives at {1}", person.Name, person.MailingAddress == null ? (String)null : person.MailingAddress.Street);
Is there a simpler way to say express this?
This code is technically a violation of the Law of Demeter , so some would consider it bad form to write this in the first place.
So no, there's no native syntax to accomplish what you want, but moving this code to a property in your Person
class would make this calling code more clean, and also bring you in line with the law of demeter.
public string StreetAddress{
get { return this.MailingAddress == null ?
(String)null : person.MailingAddress.Street; }
}
There's not really any good syntax for this. The coalesce operator is part of it, but you need to handle traversing through a null, not just replacing a null. One thing you could do would be to have a static "null object" for the class, something like:
public class Address
{
public static Address Null = new Address();
// Rest of the class goes here
}
Then you could use the coalesce operator like so:
(person.MailingAddress ?? Address.Null).Street
If you want to go the extension method route, you could do something like this:
public static class NullExtension
{
public static T OrNew<T>(this T thing)
where T: class, new()
{
return thing ?? new T();
}
}
Then you could do:
(person.MailingAddress.OrNew().Street)
You could use a device based on expression trees, so you'd write
var n = person.NullPropagate(p => p.Contact.MailingAddress.StreetAddress.Number);
/* having the effect of:
(person == null)
? defaultValue
: (person.Contact == null)
? defaultValue
: (person.Contact.MailingAddress == null)
? defaultValue
: (person.Contact.MailingAddress.StreetAddress == null)
? defaultValue
: person.Contact.MailingAddress.StreetAddress.Number;
*/
Disclaimer : I haven't written this code, I just don't know where I originally found it either. Anyone recognize this helper?
public static R NullPropagate<T, R>(this T source, Expression<Func<T, R>> expression, R defaultValue)
{
var safeExp = Expression.Lambda<Func<T, R>>(
WrapNullSafe(expression.Body, Expression.Constant(defaultValue)),
expression.Parameters[0]);
var safeDelegate = safeExp.Compile();
return safeDelegate(source);
}
private static Expression WrapNullSafe(Expression expr, Expression defaultValue)
{
Expression obj;
Expression safe = expr;
while (!IsNullSafe(expr, out obj))
{
var isNull = Expression.Equal(obj, Expression.Constant(null));
safe = Expression.Condition (isNull, defaultValue, safe);
expr = obj;
}
return safe;
}
private static bool IsNullSafe(Expression expr, out Expression nullableObject)
{
nullableObject = null;
if (expr is MemberExpression || expr is MethodCallExpression)
{
Expression obj;
MemberExpression memberExpr = expr as MemberExpression;
MethodCallExpression callExpr = expr as MethodCallExpression;
if (memberExpr != null)
{
// Static fields don't require an instance
FieldInfo field = memberExpr.Member as FieldInfo;
if (field != null && field.IsStatic)
return true;
// Static properties don't require an instance
PropertyInfo property = memberExpr.Member as PropertyInfo;
if (property != null)
{
MethodInfo getter = property.GetGetMethod();
if (getter != null && getter.IsStatic)
return true;
}
obj = memberExpr.Expression;
}
else
{
// Static methods don't require an instance
if (callExpr.Method.IsStatic)
return true;
obj = callExpr.Object;
}
// Value types can't be null
if (obj.Type.IsValueType)
return true;
// Instance member access or instance method call is not safe
nullableObject = obj;
return false;
}
return true;
}
You can use this Extension method:
public static TResult Maybe<TInput, TResult>(this TInput value, Func<TInput, TResult> evaluator, TResult failureValue)
where TInput : class
{
return (value != null) ? evaluator(value) : failureValue;
}
Example:
person.MailingAddress.MayBe(p=>p.Street,default(Street))
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.