5

我有一个具有以下 API 的第三方库:

 Update<TReport>(object updateOnly, Expression<Func<TReport,bool>> where)

我想要做的是调用此方法,但使用匿名对象,例如:

Update(new {Name = "test"}, new {Id = id})

是否可以获取第二个匿名对象并将其转换为:

x => x.Id == id.

所以我想要的是将新的 {Id = id} 转换为一个接受 TReport 并返回 bool 的函数?

4

2 回答 2

2

即使我同意 Daniel A. White 的观点,即这会使事情变得复杂,但我还是尝试了一些。

但这并不安全,因为你是losing strong typing. (你可以把你想要的任何东西放在一个匿名对象中:它没有链接到对象的“真实”属性......所以没有重构,没有检查......)

它没有经过真正的测试,所以不确定这是否是你想要的。您可以在“谓词对象”中拥有(如果有效)不同的对象:

new {Name="test"}, new{Id=1, Name="test2"})

所以,你可以有这样的东西:

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)));
        }
}

用法,例如

public void Update<TReport>(object updateOnly, object predicateObject) {
   var predicate = predicateObject.CreatePredicate<TReport>();
   yourGenericApi.Update(updateOnly, predicate);
}

编辑:当你失去强大的打字安全性时,你应该添加类似的东西

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 objectDictionary = MakeDictionary(predicateObject);
于 2012-08-02T12:10:19.613 回答
0

如果您希望函数返回一个特定的值,我认为您可以简单地执行以下操作:

bool desiredResult = true;
Update(new { Name = "test" }, x => desiredResult);
于 2012-08-02T11:06:08.583 回答