如何创建C#反射到Lambda表达式返回布尔值

时间:2015-05-08 15:50:38

标签: c# linq generics reflection expression

我有一个规范界面和类:

 ////Animate\\\\\


var imageLinks = ["http://i.imgur.com/iUjHm4e.jpg",
    "http://i.imgur.com/89Bh81C.jpg",
    "http://i.imgur.com/qKecE0F.jpg",
    "http://i.imgur.com/s5LzrE1.jpg",
    "http://i.imgur.com/thRmkE8.jpg",
    "http://i.imgur.com/mjfqeKv.jpg",
    "http://i.imgur.com/w9EpXNq.jpg",
    "http://i.imgur.com/b2rP5RQ.jpg",
    "http://i.imgur.com/NDLm5QQ.jpg",
    "http://i.imgur.com/7nohNKf.jpg",
    "http://i.imgur.com/4Qtz8KB.jpg",
    "http://i.imgur.com/xTwSsBe.jpg",
    "http://i.imgur.com/KwXNQjR.jpg",
    "http://i.imgur.com/5BVvvci.jpg",
    "http://i.imgur.com/bU0jnnD.jpg",
    "http://i.imgur.com/YKy6K6u.jpg",

];

function display(src) {
    var img = document.createElement("img");
    img.src = src;
    document.body.appendChild(img);
}

function remove(img) {
    document.body.removeChild(img);
}



i = 0;

function animation_loop() {
    im = display(imageLinks[i]);
    setTimeout(function () {
        i++;
        if (i < imageLinks.length) {
            animation_loop();
        }
    }, 50);
    remove(imageLinks[i]);
};


animation_loop();

我创建了一个Table1BySpecification,因此我可以从一个通用函数运行......

public interface ISpecification<TEntity> where TEntity : class, new()
{
    Expression<Func<TEntity, bool>> SatisfiedBy();
}

public abstract class Specification<TEntity> : ISpecification<TEntity> where TEntity : class, new()
{
    public abstract Expression<Func<TEntity, bool>> SatisfiedBy();
    public static Specification<TEntity> operator &(Specification<TEntity> leftSideSpecification, Specification<TEntity> rightSideSpecification)
    {
        return new AndSpecification<TEntity>(leftSideSpecification, rightSideSpecification);
    }
    public static Specification<TEntity> operator |(Specification<TEntity> leftSideSpecification, Specification<TEntity> rightSideSpecification)
    {
        return new OrSpecification<TEntity>(leftSideSpecification, rightSideSpecification);
    }
    public static Specification<TEntity> operator !(Specification<TEntity> specification)
    {
        return new NotSpecification<TEntity>(specification);
    }
    public static bool operator false(Specification<TEntity> specification)
    {
        return false;
    }
    public static bool operator true(Specification<TEntity> specification)
    {
        return true;
    }
}

public class Table1BySpecification: Specification<Table1>
{
    Propiedades Privadas
    Expression<Func<Table1, bool>> _Expression = null;

    public Table1BySpecification(Expression<Func<Table1, bool>> expression)
    {
        this._Expression = expression;
    }

    public override Expression<Func<Table1, bool>> SatisfiedBy()
    {
        return this._Expression;
    }
}

这适用于Table1实体,但是我想使用TEntity,并使用反射使用动态规范。也许我可以有类似的东西:

public IEnumerable<TEntity> GetBySpecification(string propertyName, object propertyValue, propertyOperator ){

    ISpecification<Table1> Specification = new Table1BySpecification(t1 => t1.name == "test_name");          
    context.CreateDbSet<Table1>().Where(Specification.SatisfiedBy())
}

我不知道这个代码是否可以成为解决方案的一部分,以便至少在propertyName变量方面创建( Reflection_Expression )。 我真的无法创建( Reflection_Expression )作为lambda表达式,最后得到 Reflection_Expression ......的实施。

public IEnumerable<TEntity> GetBySpecification(string propertyName = "name", object propertyValue = "test_name", string propertyOperator = "==" ){

    var source = typeof(TEntity); 
    var t = Expression.Parameter( source, "t" );
    var sourceProperty = Expression.MakeMemberAccess( arg, source.GetProperty( propertyName ) );
    PropertyInfo propertyField = type.GetProperty(propertyName);
    Type propertyType = propertyField.GetType();

    PropertyInfo[] props = typeof(TEntity).GetProperties();
    foreach (PropertyInfo prop in props)
    {
        var displayAttribute = prop.GetCustomAttributes(false).FirstOrDefault(a => a.GetType() == propertyType);
        if (displayAttribute != null)
        {
            var parameterExpression = Expression.Parameter(typeof(TEntity), "x");
            var memberExpression = Expression.PropertyOrField(parameterExpression, prop.Name);
            var memberExpressionConversion = Expression.Convert(memberExpression, typeof(object));
            var lambda = Expression.Lambda<Func<TEntity, object>>(memberExpressionConversion, parameterExpression);                    
        }
    }

    ISpecification<TEntity> Specification = new EntityByCustomSpecification<TEntity>(***Reflection_Expression***);

    context.CreateDbSet<TEntity>().Where(Specification.SatisfiedBy()),
}

...当TEntity为t1时,propertyName为name,其value propertyValue为“test_name”,运算符propertyOperator为“==”

任何帮助,请????

非常感谢!

1 个答案:

答案 0 :(得分:3)

鉴于

public class EntityByCustomSpecification<TEntity> : Specification<TEntity> where TEntity : class, new()
{
    Expression<Func<TEntity, bool>> _Expression = null;

    public EntityByCustomSpecification(Expression<Func<TEntity, bool>> expression)
    {
        this._Expression = expression;
    }

    public override Expression<Func<TEntity, bool>> SatisfiedBy()
    {
        return this._Expression;
    }
}

(目前尚不清楚你是否已经拥有它)

你想要的是:

public IEnumerable<TEntity> GetBySpecification<TEntity>(object propertyValue, string propertyName = "name", ExpressionType operation = ExpressionType.Equal) where TEntity : class, new()
{
    ParameterExpression par = Expression.Parameter(typeof(TEntity));

    Expression left = Expression.PropertyOrField(par, propertyName);
    Expression right = Expression.Constant(propertyValue, left.Type);

    Expression comparison;

    try
    {
        comparison = Expression.MakeBinary(operation, left, right);
    }
    catch (InvalidOperationException)
    {
        // string case, for example
        Type icomparable = typeof(IComparable<>).MakeGenericType(left.Type);

        if (!left.Type.GetInterfaces().Any(x => x == icomparable))
        {
            throw;
        }

        InterfaceMapping interfaceMap = left.Type.GetInterfaceMap(icomparable);
        int ix = Array.FindIndex(interfaceMap.InterfaceMethods, x => x.Name == "CompareTo");
        MethodInfo method = interfaceMap.TargetMethods[ix];

        // left.CompareTo(right) [operation] 0
        comparison = Expression.MakeBinary(operation, Expression.Call(left, method, right), Expression.Constant(0));
    }

    if (comparison.Type != typeof(bool))
    {
        throw new ArgumentException("operationType");
    }

    Expression<Func<TEntity, bool>> lambda = Expression.Lambda<Func<TEntity, bool>>(comparison, par);

    ISpecification<TEntity> specification = new EntityByCustomSpecification<TEntity>(lambda);

    var result = context.Set<TEntity>().Where(specification.SatisfiedBy());
    return result;
}

请注意,要使其更简单,它会接受string propertyOperator而不是ExpressionTypeExpressionType包含所有比较运算符(<<===>=>),以及您可以忽略的数学运算符(+- ...)。您可以轻松编写一个方法,让string返回正确的ExpressionType

我已经纠正了可空类型的错误。我已通过string界面添加了对IComparable<T>的支持。