将匿名对象转换为表达式委托

时间:2012-08-02 10:57:46

标签: c#

我有第三方库,其中包含以下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的函数?

2 个答案:

答案 0 :(得分:2)

即使我同意丹尼尔·A·怀特(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);

答案 1 :(得分:0)

如果你有一个特定的值,你希望函数返回,我想你可以这样做:

bool desiredResult = true;
Update(new { Name = "test" }, x => desiredResult);