2

I have a situation where I have just the property name (string) and the value by which desire filter. I need to filter the list to return true if any name repeated.

Remembering that the filter should exclude it yourself. With expression like: p => p.Id != currentId

Code

As the property is a string, I decided to create a Dynamic Expression to solve this problem.

[TestMethod]
public void TestingExpression()
{
    // Arrange
    var fix = new Fixture();
    var list = fix.Build<User>()
                    .With(p => p.Name)
                    .OmitAutoProperties()
                    .CreateMany(20).AsQueryable(); // Create IQueryable<User> with 20 users

    // Act 
    var currentId = 2;
    var uniquePropName = "Name";
    var uniqueValue = "{NotFoundValue}";

    // Expression: p => p.Id != currentId
    ParameterExpression pId = Expression.Parameter(typeof(int), "Id");
    ConstantExpression cId = Expression.Constant(currentId, typeof(int));
    BinaryExpression notCurrent = Expression.NotEqual(pId, cId);
    Expression<Func<int, bool>> NotCurrentExpr =
        Expression.Lambda<Func<int, bool>>(
            notCurrent,
            new ParameterExpression[] { pId });

    // Expression: p.{uniquePropName} == {uniqueValue}
    ParameterExpression pUnique = Expression.Parameter(typeof(string), uniquePropName);
    ConstantExpression cUnique = Expression.Constant(uniqueValue, typeof(string));
    BinaryExpression checkUnique = Expression.Equal(pUnique, cUnique);
    Expression<Func<string, bool>> CheckUniqueExp =
        Expression.Lambda<Func<string, bool>>(
            checkUnique,
            new ParameterExpression[] { pUnique });


    var exp = Expression.And(NotCurrentExpr, CheckUniqueExp);

    // Asset
    list.Provider.CreateQuery<User>(exp).ToList()
            .Should().HaveCount(19);

}

Question

The goal is to create a dynamic expression as: query.Any(p => p.Id != id && p.{Dynamic} == nome);

But I do not know how to continue ..

Thanks

ridermansb
  • 10,779
  • 24
  • 115
  • 226
  • Possible same question: http://stackoverflow.com/questions/1689199/c-sharp-code-against-a-property-using-the-property-name-as-a-string – Bryan Hong May 27 '13 at 01:12
  • @BryanHong Not the same question! As you can see my code does not use reflection. Another detail is that my doubt is how to apply the expressions in my IQueryable. The issues are similar, but not the same. – ridermansb May 27 '13 at 01:27

1 Answers1

1

A nice tutorial can be found here.

You seem to be confusing the parameters and properties. Here is a further example:

//user => user.SomeProperty == someValue

//the parameter of the predicate, a User object in your case 
ParameterExpression parameter = Expression.Parameter(typeof(User), "user");

//the property of the user object to use in expression
Expression property = Expression.Property(parameter, myPropertyNameString);

//the value to compare to the user property
Expression val = Expression.Constant(myValueToCompare);

//the binary expression using the above expressions
BinaryExpression expEquals = Expression.Equal(property, val);

//create the Expression<Func<T, Boolean>>
var predicate = Expression.Lambda<Func<User, Boolean>>(expEquals, parameter);

Furthermore in your code you try and create two lambdas whereas your aim is to produce

p => p.Id != id && p.{Dynamic} == nome

This is a single lambda that takes 1 parameter with the body consisting of two binary expressions and a conditional AND operator producing a Boolean result. You should instead use Expression.AndAlso() to apply the && operator to your binary expressions and then use Expression.Lambda<Func<User, Boolean>>() to get your final lambda expression.

  • Sorry for delay: I have a error > System.ArgumentException: Expression of type 'System.Func`2[CreditoImobiliarioBB.Model.Modalidade,System.Int32]' cannot be used for return type 'System.Int32' in `Expression> lambdaExpr = Expression.Lambda>(PropertyId);` My expression is `private readonly Expression> PropertyId;` – ridermansb Jul 05 '13 at 14:21
  • See this: https://fluentvalidation.codeplex.com/discussions/353331#post1050039 In line `var currentId = Expression.Lambda>(PropertyId).Compile()(); // Get Current ID` I get the error. `System.ArgumentException: Expression of type 'System.Func`2[CreditoImobiliarioBB.Model.Modalidade,System.Int32]' cannot be used for return type 'System.Int32'` – ridermansb Jul 05 '13 at 14:48
  • @Ridermansb, more detail added. Look at the tutorial I linked to, what you're trying to do is very similar to it. –  Jul 06 '13 at 01:15
  • yes, I read the article. I admit, I am not an expert in lambdas :) I think you've answered the question. The problem is that I can not retrieve the value passed to the function through `.MustBeUnique(p => p.Id, repositorio);` (Id value), so I can not test the expression. See [full error here](https://gist.github.com/Ridermansb/22239f8fce8d0f58f71b) In my class, I have `private readonly Expression> PropertyId;` property. Need to get int value for this expression. – ridermansb Jul 06 '13 at 13:57