123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279 |
- using System;
- using System.Linq;
- using System.Linq.Expressions;
- using System.Reflection;
- namespace InABox.Core
- {
- public static class Expressions
- {
- #region Property Getter Setter Functions
- // Allows setting of object properties via cached expressions
- public static Func<T, object> Getter<T>(string propname)
- {
- 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();
- }
- catch (Exception e)
- {
- Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
- }
- return result;
- }
- public static Func<object, object> Getter(Type objectType, string propname)
- {
- 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 result;
- }
- public static Func<T, object> Getter<T>(string propname, string key)
- {
- Func<T, object> result = null;
- try
- {
- var param = Expression.Parameter(typeof(T), "o");
- Expression body = param;
- foreach (var member in propname.Split('.'))
- body = Expression.PropertyOrField(body, member);
- Expression keyExpr = Expression.Constant(key, typeof(string)); //Parameter(typeof(string));
- // Alternative, note that we could even look for the type of parameters, if there are indexer overloads.
- var indexer = (from p in body.Type.GetDefaultMembers().OfType<PropertyInfo>()
- // This check is probably useless. You can't overload on return value in C#.
- where p.PropertyType == typeof(object)
- let q = p.GetIndexParameters()
- // Here we can search for the exact overload. Length is the number of "parameters" of the indexer, and then we can check for their type.
- where q.Length == 1 && q[0].ParameterType == typeof(string)
- select p).Single();
- var indexExpr = Expression.Property(body, indexer, keyExpr);
- var lambdaGetter = Expression.Lambda<Func<T, object>>(indexExpr, param);
- result = lambdaGetter.Compile();
- }
- catch (Exception e)
- {
- Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
- }
- return result;
- }
- public static Func<object, object> Getter(Type objectType, string propname, string key)
- {
- 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 keyExpr = Expression.Constant(key, typeof(string)); //Parameter(typeof(string));
- // Alternative, note that we could even look for the type of parameters, if there are indexer overloads.
- var indexer = (from p in body.Type.GetDefaultMembers().OfType<PropertyInfo>()
- // This check is probably useless. You can't overload on return value in C#.
- where p.PropertyType == typeof(object)
- let q = p.GetIndexParameters()
- // Here we can search for the exact overload. Length is the number of "parameters" of the indexer, and then we can check for their type.
- where q.Length == 1 && q[0].ParameterType == typeof(string)
- select p).Single();
- var indexExpr = Expression.Property(body, indexer, keyExpr);
- var lambdaGetter = Expression.Lambda<Func<object, object>>(indexExpr, objectParameter);
- result = lambdaGetter.Compile();
- }
- catch (Exception e)
- {
- Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
- }
- return result;
- }
- public static Action<T, object> Setter<T>(string propname)
- {
- var param = Expression.Parameter(typeof(T), "o");
- Expression body = param;
- foreach (var member in propname.Split('.'))
- body = Expression.PropertyOrField(body, member);
- var valueParameter = Expression.Parameter(typeof(object), "v");
- var value = Expression.ConvertChecked(valueParameter, body.Type);
- Expression expression = null;
- try
- {
- expression = Expression.Assign(body, value);
- }
- catch (Exception e)
- {
- expression = Expression.Empty();
- }
- var lambda = Expression.Lambda<Action<T, object>>(expression, param, valueParameter);
- var compiled = lambda.Compile();
- return compiled;
- }
- public static Action<object, object> Setter(Type objectType, string propname, Type type = null)
- {
- Action<object, object> compiled = 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);
- var valueParameter = Expression.Parameter(typeof(object), "v");
- UnaryExpression value = null;
- if (type != null)
- {
- var val1 = Expression.Convert(valueParameter, type);
- value = Expression.ConvertChecked(val1, body.Type);
- }
- else
- {
- value = Expression.ConvertChecked(valueParameter, body.Type);
- }
- Expression expression = null;
- try
- {
- expression = Expression.Assign(body, value);
- }
- catch (Exception e)
- {
- expression = Expression.Empty();
- }
- var lambda = Expression.Lambda<Action<object, object>>(expression, objectParameter, valueParameter);
- compiled = lambda.Compile();
- }
- catch (Exception e)
- {
- Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
- }
- return compiled;
- }
- public static Action<T, object> Setter<T>(string propname, string key)
- {
- Action<T, object> result = null;
- try
- {
- var param = Expression.Parameter(typeof(T), "o");
- Expression body = param;
- foreach (var member in propname.Split('.'))
- body = Expression.PropertyOrField(body, member);
- Expression keyExpr = Expression.Constant(key, typeof(string));
- var valueExpr = Expression.Parameter(typeof(object));
- // Alternative, note that we could even look for the type of parameters, if there are indexer overloads.
- var indexer = (from p in body.Type.GetDefaultMembers().OfType<PropertyInfo>()
- // This check is probably useless. You can't overload on return value in C#.
- where p.PropertyType == typeof(object)
- let q = p.GetIndexParameters()
- // Here we can search for the exact overload. Length is the number of "parameters" of the indexer, and then we can check for their type.
- where q.Length == 1 && q[0].ParameterType == typeof(string)
- select p).Single();
- var indexExpr = Expression.Property(body, indexer, keyExpr);
- var assign = Expression.Assign(indexExpr, valueExpr);
- var lambdaSetter = Expression.Lambda<Action<T, object>>(assign, param, valueExpr);
- result = lambdaSetter.Compile();
- }
- catch (Exception e)
- {
- Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
- }
- return result;
- }
- public static Action<object, object> Setter(Type objectType, string propname, string key)
- {
- Action<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 keyExpr = Expression.Constant(key, typeof(string));
- var valueExpr = Expression.Parameter(typeof(object));
- // Alternative, note that we could even look for the type of parameters, if there are indexer overloads.
- var indexer = (from p in body.Type.GetDefaultMembers().OfType<PropertyInfo>()
- // This check is probably useless. You can't overload on return value in C#.
- where p.PropertyType == typeof(object)
- let q = p.GetIndexParameters()
- // Here we can search for the exact overload. Length is the number of "parameters" of the indexer, and then we can check for their type.
- where q.Length == 1 && q[0].ParameterType == typeof(string)
- select p).Single();
- var indexExpr = Expression.Property(body, indexer, keyExpr);
- var assign = Expression.Assign(indexExpr, valueExpr);
- var lambdaSetter = Expression.Lambda<Action<object, object>>(assign, objectParameter, valueExpr);
- result = lambdaSetter.Compile();
- }
- catch (Exception e)
- {
- Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
- }
- return result;
- }
- #endregion
- }
- }
|