Last active
December 6, 2018 10:39
-
-
Save charlessolar/20f453de023ff75edeb8 to your computer and use it in GitHub Desktop.
Building objects from a list of property names for Dynamic DTOs - useful for authorization field level filtering and situations when you don't know the type of data a service will return
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static IQueryable<dynamic> ToDynamic<T>(this IQueryable<T> query, ISet<String> fields) | |
{ | |
var pocoType = typeof(T); | |
var itemParam = Expression.Parameter(pocoType, "x"); | |
var members = fields.Select(f => Expression.PropertyOrField(itemParam, f)); | |
var addMethod = typeof(IDictionary<string, object>).GetMethod( | |
"Add", new Type[] { typeof(string), typeof(object) }); | |
var elementInits = members.Select(m => Expression.ElementInit(addMethod, Expression.Constant(m.Member.Name), Expression.Convert(m, typeof(Object)))); | |
var expando = Expression.New(typeof(ExpandoObject)); | |
var lambda = Expression.Lambda<Expression<Func<T, dynamic>>>(Expression.ListInit(expando, elementInits), itemParam); | |
return query.Select(lambda.Compile()); | |
} | |
public static IQueryable<T> FromDynamic<T>(this IQueryable<dynamic> query) where T : class, new() | |
{ | |
var itemParam = Expression.Parameter(typeof(ExpandoObject), "x"); | |
var members = typeof(T).GetProperties().Where(p => p.CanWrite).Select(f => Expression.Property(itemParam, f)); | |
var selector = Expression.MemberInit(Expression.New(typeof(T)), | |
members.Select(m => Expression.Bind(typeof(T).GetMember(m.Member.Name).Single(), m)) | |
); | |
var lambda = Expression.Lambda<Expression<Func<dynamic, T>>>(selector, itemParam); | |
return query.Select(lambda.Compile()); | |
} | |
public static T FromDynamic<T>(this IDictionary<string, object> dictionary) where T : class, new() | |
{ | |
var bindings = new List<MemberBinding>(); | |
foreach (var sourceProperty in typeof(T).GetProperties().Where(x => x.CanWrite)) | |
{ | |
var key = dictionary.Keys.SingleOrDefault(x => x.Equals(sourceProperty.Name, StringComparison.OrdinalIgnoreCase)); | |
if (string.IsNullOrEmpty(key)) continue; | |
var propertyValue = dictionary[key]; | |
bindings.Add(Expression.Bind(sourceProperty, Expression.Constant(propertyValue))); | |
} | |
Expression memberInit = Expression.MemberInit(Expression.New(typeof(T)), bindings); | |
return Expression.Lambda<Func<T>>(memberInit).Compile().Invoke(); | |
} | |
public static dynamic ToDynamic<T>(this T obj, ISet<String> fields) | |
{ | |
IDictionary<string, object> expando = new ExpandoObject(); | |
var pocoType = typeof(T); | |
foreach (var f in fields) | |
{ | |
var propertyExpression = Expression.Property(Expression.Constant(obj), pocoType.GetProperty(f)); | |
var currentValue = Expression.Lambda<Func<string>>(propertyExpression).Compile().Invoke(); | |
expando.Add(f, currentValue); | |
} | |
return expando as ExpandoObject; | |
} |
I was unable to get it work with .Net 4.5. Another way: https://gist.github.com/gh0stwizard/e2394cf09cd1eac01c1e5a3c22e0d014
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@cmalcom line 15 should be chamged to
var lambda = Expression.Lambda<Func<T, dynamic>>(Expression.ListInit(expando, elementInits), itemParam)
lambda is now of type Expression<Func<T, dynamic>>
and final on line 17
return query.Select(lambda.Compile());
you can leave out the call to Compile()return query.Select(lambda);