|
@@ -1,4 +1,7 @@
|
|
|
-using System;
|
|
|
+using InABox.Clients;
|
|
|
+using System;
|
|
|
+using System.Collections.Generic;
|
|
|
+using System.ComponentModel;
|
|
|
using System.Linq;
|
|
|
using System.Linq.Expressions;
|
|
|
using System.Reflection;
|
|
@@ -11,51 +14,71 @@ namespace InABox.Core
|
|
|
|
|
|
// Allows setting of object properties via cached expressions
|
|
|
|
|
|
- public static Func<T, TValue> Getter<T, TValue>(Expression<Func<T, TValue>> expression)
|
|
|
+ public static Expression NullPropagatingPropertyOrField(Expression expression, string propName)
|
|
|
{
|
|
|
- return expression.Compile();
|
|
|
+ var param = Expression.Parameter(expression.Type);
|
|
|
+ var access = Expression.PropertyOrField(param, propName);
|
|
|
+ return Expression.Block(new[] { param },
|
|
|
+ Expression.Assign(param, expression),
|
|
|
+ Expression.Condition(Expression.Equal(param, Expression.Constant(null)),
|
|
|
+ Expression.Default(access.Type),
|
|
|
+ access));
|
|
|
}
|
|
|
|
|
|
- public static Func<T, object> Getter<T>(string propname)
|
|
|
+ private static Func<T, TProp>? MakeGetter<T, TProp>(Type objectType, string propname, bool propagateNulls = false)
|
|
|
{
|
|
|
- Func<T, object>? result = null;
|
|
|
try
|
|
|
{
|
|
|
- var param = Expression.Parameter(typeof(T), "x");
|
|
|
- Expression body = param;
|
|
|
- foreach (var member in propname.Split('.'))
|
|
|
- body = Expression.PropertyOrField(body, member);
|
|
|
- var lambda = Expression.Lambda<Func<T, object>>(body, param);
|
|
|
- result = lambda.Compile();
|
|
|
+ var objectParameter = Expression.Parameter(typeof(T), "o");
|
|
|
+ Expression param;
|
|
|
+ if(typeof(T) != objectType)
|
|
|
+ {
|
|
|
+ param = Expression.ConvertChecked(objectParameter, objectType);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ param = objectParameter;
|
|
|
+ }
|
|
|
+
|
|
|
+ var body = param;
|
|
|
+ if(propname != "")
|
|
|
+ {
|
|
|
+ foreach (var member in propname.Split('.'))
|
|
|
+ body = propagateNulls
|
|
|
+ ? NullPropagatingPropertyOrField(body, member)
|
|
|
+ : Expression.PropertyOrField(body, member);
|
|
|
+ }
|
|
|
+
|
|
|
+ if(typeof(TProp) != body.Type)
|
|
|
+ {
|
|
|
+ body = Expression.Convert(body, typeof(TProp));
|
|
|
+ }
|
|
|
+
|
|
|
+ var lambda = Expression.Lambda<Func<T, TProp>>(body, objectParameter);
|
|
|
+ return lambda.Compile();
|
|
|
}
|
|
|
catch (Exception e)
|
|
|
{
|
|
|
Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
|
|
|
+ return null;
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- return result;
|
|
|
+ public static Func<T, TValue> Getter<T, TValue>(Expression<Func<T, TValue>> expression, bool propagateNulls = false)
|
|
|
+ {
|
|
|
+ return propagateNulls
|
|
|
+ ? MakeGetter<T, TValue>(typeof(T), CoreUtils.GetFullPropertyName(expression, "."), propagateNulls: true)
|
|
|
+ : expression.Compile();
|
|
|
}
|
|
|
|
|
|
- public static Func<object, object> Getter(Type objectType, string propname)
|
|
|
+ public static Func<T, object> Getter<T>(string propname, bool propagateNulls = false)
|
|
|
{
|
|
|
- Func<object, object> result = null;
|
|
|
- try
|
|
|
- {
|
|
|
- var objectParameter = Expression.Parameter(typeof(object), "o");
|
|
|
- var param = Expression.ConvertChecked(objectParameter, objectType);
|
|
|
- Expression body = param;
|
|
|
- foreach (var member in propname.Split('.'))
|
|
|
- body = Expression.PropertyOrField(body, member);
|
|
|
- Expression conversion = Expression.Convert(body, typeof(object));
|
|
|
- var lambda = Expression.Lambda<Func<object, object>>(conversion, objectParameter);
|
|
|
- result = lambda.Compile();
|
|
|
- }
|
|
|
- catch (Exception e)
|
|
|
- {
|
|
|
- Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
|
|
|
- }
|
|
|
+ return MakeGetter<T, object>(typeof(T), propname, propagateNulls: propagateNulls);
|
|
|
+ }
|
|
|
|
|
|
- return result;
|
|
|
+ public static Func<object, object> Getter(Type objectType, string propname, bool propagateNulls = false)
|
|
|
+ {
|
|
|
+ return MakeGetter<object, object>(objectType, propname, propagateNulls: propagateNulls);
|
|
|
}
|
|
|
|
|
|
public static Func<T, object> Getter<T>(string propname, string key)
|