我有一个第三方库,它有以下API:
Update<TReport>(object updateOnly, Expression<Func<TReport,bool>> where)
Run Code Online (Sandbox Code Playgroud)
我想要做的是调用此方法,但使用匿名对象,如:
Update(new {Name = "test"}, new {Id = id})
Run Code Online (Sandbox Code Playgroud)
是否可以获取第二个匿名对象并将其转换为:
x => x.Id == id.
Run Code Online (Sandbox Code Playgroud)
所以我想要的是将新的{Id = id}转换为一个接受TReport并返回bool的函数?
即使我同意 Daniel A. White 的观点,即这会使事情变得复杂,但我还是尝试了一些。
但这并不安全,因为你losing strong typing。(您可以将任何您想要的内容放入匿名对象中:它不链接到对象的“真实”属性......所以没有重构,没有检查......)
它没有经过真正的测试,所以不确定这是否是你想要的。您可以在“谓词对象”中拥有(如果有效)不同的对象:
new {Name="test"}, new{Id=1, Name="test2"})
Run Code Online (Sandbox Code Playgroud)
所以,你可以有这样的东西:
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)));
}
}
Run Code Online (Sandbox Code Playgroud)
用法,例如
public void Update<TReport>(object updateOnly, object predicateObject) {
var predicate = predicateObject.CreatePredicate<TReport>();
yourGenericApi.Update(updateOnly, predicate);
}
Run Code Online (Sandbox Code Playgroud)
编辑:当您失去强大的打字安全性时,您应该添加类似的内容
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));
}
Run Code Online (Sandbox Code Playgroud)
后
var objectDictionary = MakeDictionary(predicateObject);
Run Code Online (Sandbox Code Playgroud)