【问题标题】:Create Dynamic Func<T, TResult> from Object从对象创建动态 Func<T, TResult>
【发布时间】:2013-07-18 06:59:13
【问题描述】:

我有一个条件对象,如果它的值不为 null,我将在其中将每个属性转换为 func。

public class TestClassCriteria
{
    public bool? ColumnA { get; set; }
    public bool? ColumnB { get; set; }
}

这是我迄今为止所拥有的,但我很确定我没有正确定义 lambda。这就是我想要达到的目标。 funcs.Add(x =&gt; x.ColumnA == criteria.ColumnA).

var properties = criteria.GetType().GetProperties();
var funcs = new List<Func<dynamic, bool>>();

foreach (var property in properties)
{
    var propertyName = property.Name;

    funcs.Add(x => x.GetType().GetProperty(propertyName).Name == criteria.GetType().GetProperty(propertyName).Name);
}

它没有崩溃或导致任何错误,它只是不工作。

您能提供的任何帮助将不胜感激。

【问题讨论】:

  • 好吧,首先,lambda 应该有花括号,所以你需要将 x => x.ColumnA == criteria.ColumnA 更改为 (x) => {x.ColumnA = = 标准.ColumnA;}。我还认为您希望它返回一个布尔值,在这种情况下它将变为 (x) => {return x.ColumnA == criteria.ColumnA;}。不过,我不能 100% 确定您要做什么。
  • @Pharap "lambdas 应该有花括号" 不是很正确...{} 也阻止将 lambda 用作表达式(据我了解,这大约是 OP 试图做的事情),但允许使用多个语句创建委托。

标签: c# dynamic reflection lambda expression


【解决方案1】:

你想要这样的东西吗?

    static List<Func<TEntity, TCriteria, bool>> GetCriteriaFunctions<TEntity, TCriteria>()
    {
        var criteriaFunctions = new List<Func<TEntity, TCriteria, bool>>();

        // searching for nullable properties of criteria
        var criteriaProperties = typeof(TCriteria)
            .GetProperties()
            .Where(p => p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>));

        foreach (var property in criteriaProperties)
        {
            // this is entity parameter
            var entityParameterExpression = Expression.Parameter(typeof(TEntity));
            // this is criteria parameter
            var criteriaParameterExpression = Expression.Parameter(typeof(TCriteria));
            // this is criteria property access: "criteria.SomeProperty"
            var criteriaPropertyExpression = Expression.Property(criteriaParameterExpression, property);
            // this is testing for equality between criteria property and entity property;
            // note, that criteria property should be converted first;
            // also, this code makes assumption, that entity and criteria properties have the same names
            var testingForEqualityExpression = Expression.Equal(
                Expression.Convert(criteriaPropertyExpression, property.PropertyType.GetGenericArguments()[0]), 
                Expression.Property(entityParameterExpression, property.Name));

            // criteria.SomeProperty == null ? true : ((EntityPropertyType)criteria.SomeProperty == entity.SomeProperty)
            var body = Expression.Condition(
                Expression.Equal(criteriaPropertyExpression, Expression.Constant(null)), 
                Expression.Constant(true),
                testingForEqualityExpression);

            // let's compile lambda to method
            var criteriaFunction = Expression.Lambda<Func<TEntity, TCriteria, bool>>(body, entityParameterExpression, criteriaParameterExpression).Compile();

            criteriaFunctions.Add(criteriaFunction);
        }

        return criteriaFunctions;
    }

样本实体和样本标准:

class CustomerCriteria
{
    public int? Age { get; set; }
    public bool? IsNew { get; set; }
}

class Customer
{
    public string Name { get; set; }
    public int Age { get; set; }
    public bool IsNew { get; set; }
}

用法:

        var criteriaFunctions = GetCriteriaFunctions<Customer, CustomerCriteria>();
        var customer1 = new Customer { Name = "John", Age = 35, IsNew = false };
        var customer2 = new Customer { Name = "Mary", Age = 27, IsNew = true };
        var criteria1 = new CustomerCriteria { Age = 35 };
        var criteria2 = new CustomerCriteria { IsNew = true };

        Console.WriteLine("Is match: {0}", criteriaFunctions.All(f => f(customer1, criteria1)));
        Console.WriteLine("Is match: {0}", criteriaFunctions.All(f => f(customer2, criteria1)));
        Console.WriteLine("Is match: {0}", criteriaFunctions.All(f => f(customer1, criteria2)));
        Console.WriteLine("Is match: {0}", criteriaFunctions.All(f => f(customer2, criteria2)));

此代码使用强类型成员访问,而不是您的动态代码,因此,您可以缓存每对“实体 - 条件”的条件列表,并更快地匹配测试实例。

【讨论】:

  • 成功了,非常感谢。万一有人感兴趣,我完全按照他上面概述的方式实现了它。
【解决方案2】:

您当前的表达式是比较属性名称,但我认为您想比较属性值:

var funcs = new List<Func<dynamic, bool>>();

foreach (var property in criteria.GetType().GetProperties())
{
    funcs.Add(x => x.GetType().GetProperty(property.Name).GetValue(x, null) == property.GetValue(criteria, null));
}

但是,您确定需要这样做吗?可能会有更好的方法来重构您的代码,这样您就不需要使用反射来比较两个不相关对象上碰巧具有相同名称的属性。

【讨论】:

  • 当我尝试这个时,我得到一个错误 Microsoft.CSharp.RuntimeBinder.RuntimeBinderException : Operator '==' cannot be applied to 'bool' and 'object' 类型的操作数即使我强制转换它,它仍然无法正常工作。我认为下面的回应更多是我们需要的。我会试一试,然后告诉你。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-15
  • 1970-01-01
  • 2019-04-02
  • 1970-01-01
相关资源
最近更新 更多