I have an third party library that has the following API:
Update<TReport>(object updateOnly, Expression<Func<TReport,bool>> where)
What I want to do is call this method but using anonymous objects such as :
Update(new {Name = "test"}, new {Id = id})
Is it possible to take the second anonymous object and convert it to something like :
x => x.Id == id.
So what I want is to convert the new {Id = id} to a function that takes TReport and returns bool?
Even if I agree with Daniel A. White on the fact that it's complicating things, I tried a bit.
But it's not safe, cause you're losing strong typing
. (You can put whatever you want in an anonymous object : it's not linked to the object's "real" properties... So no refactoring, no check...)
It's not really tested, so not sure if that's what you want. You can have (if it works) different objects in the "predicate object" :
new {Name="test"}, new{Id=1, Name="test2"})
So, you could have something like that :
public static class MyHelpers
{
public static Expression<Func<TReport, bool>> CreatePredicate<TReport>(this object predicateObject)
{
var parameterExpression = Expression.Parameter(typeof(TReport), "item");
Expression memberExpression = parameterExpression;
var objectDictionary = MakeDictionary(predicateObject);
foreach (var entry in objectDictionary.Where(entry => typeof(TReport).GetProperty(entry.Key) == null))
{
throw new ArgumentException(string.Format("Type {0} has no property {1}", typeof(TReport).Name, entry.Key));
}
var equalityExpressions = GetBinaryExpressions(objectDictionary, memberExpression).ToList();
var body = equalityExpressions.First();
body = equalityExpressions.Skip(1).Aggregate(body, Expression.And);
return Expression.Lambda<Func<TReport, bool>>(body, new[] { parameterExpression });
}
private static IDictionary<string, object> MakeDictionary(object withProperties)
{
var properties = TypeDescriptor.GetProperties(withProperties);
return properties.Cast<PropertyDescriptor>().ToDictionary(property => property.Name, property => property.GetValue(withProperties));
}
private static IEnumerable<BinaryExpression> GetBinaryExpressions(IDictionary<string, object> dic, Expression expression)
{
return dic.Select(m => Expression.Equal(Expression.Property(expression, m.Key), Expression.Constant(m.Value)));
}
}
usage, for example
public void Update<TReport>(object updateOnly, object predicateObject) {
var predicate = predicateObject.CreatePredicate<TReport>();
yourGenericApi.Update(updateOnly, predicate);
}
EDIT : As you're losing strong typing security, you should add something like
foreach (var entry in objectDictionary.Where(entry => typeof(TReport).GetProperty(entry.Key) == null))
{
throw new ArgumentException(string.Format("Type {0} has no property {1}", typeof(TReport).Name, entry.Key));
}
after
var objectDictionary = MakeDictionary(predicateObject);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With