Maybe there is more
Michel Perfetti, has taken my little Maybe thingie and gone a lot further,
by using expression tree re-writting he has made it possible to express this:
string code = licensePlate.Maybe(lp => lp.Car)
.Maybe(c => c.Owner)
.Maybe(o => o.Address)
.Maybe(a => a.PostCode);
which is NULL safe but very cumbersome like this:
string code = licensePlate.Maybe2(lp => lp.Car.Owner.Address.PostCode);
which is much cleaner and still NULL safe.
Michel does this by declaring Maybe2 to take an Expression, rather than a Func i.e. it has this signature: public static V Maybe2<T, V>(this T t, Expression<Func<T, V>> expression)
Then he cracks open the expression and rewrites it to do each property access inside a call to Maybe.
Nice stuff Michel.
UPDATE: Sorry for originally getting your last name wrong Michel, and thanks Matthieu for pointing it out!
Comments
Anonymous
March 03, 2008
PingBack from http://msdnrss.thecoderblogs.com/2008/03/03/maybe-there-is-more/Anonymous
March 05, 2008
I just had to try this one step further :P public static class Null { private static readonly MethodInfo maybeMethod; static Null() { maybeMethod = typeof(Null).GetMethod("Maybe", BindingFlags.Public | BindingFlags.Static); } public static V Maybe<T, V>(this T t, Func<T, V> selector) where T : class { return t != null ? selector(t) : default(V); } public static T Try<T>(Expression<Func<T>> ex) { MemberExpression memberBody = ex.Body as MemberExpression; if (memberBody != null) { MethodCallExpression result = ConvertMemberToMethodCall(memberBody); LambdaExpression lambda = Expression.Lambda(result); return (T)lambda.Compile().DynamicInvoke(); } throw new NotSupportedException(); } private static MethodCallExpression ConvertMemberToMethodCall(MemberExpression memberExpression) { MemberExpression me = memberExpression.Expression as MemberExpression; Expression ex = me != null ? ConvertMemberToMethodCall(me) : memberExpression.Expression; Type type = null; PropertyInfo prop = memberExpression.Member as PropertyInfo; if (prop != null) { type = prop.PropertyType; } else { FieldInfo field = memberExpression.Member as FieldInfo; if (field != null) { type = field.FieldType; } } if (type == null) { throw new NotImplementedException(); } MethodInfo methodInfo = maybeMethod.MakeGenericMethod(new[] { memberExpression.Member.DeclaringType, type }); ParameterExpression p = Expression.Parameter(memberExpression.Member.DeclaringType, "p"); LambdaExpression maybeLamba = Expression.Lambda(Expression.MakeMemberAccess(p, memberExpression.Member), new[] { p }); return Expression.Call(null, methodInfo, new[] { ex, maybeLamba }); } } Which can be used as: string testString = "Test"; int length4 = Null.Try(() => testString.Length); // 4 string nullString = null; int length0 = Null.Try(() => nullString.Length); // 0Anonymous
March 06, 2008
@XIU,that is pretty cool. Nice workAlex