问题
I have this two classes:
public class Contratos
{
//...
public int EntidadeFinanceiraId { get; set; }
[Column("Nome")]
public EntidadesFinanceiras entidadeFinanceira { get; set; }
//...
}
public class EntidadesFinanceiras
{
[Key]
public int ID { get; set; }
public string Nome { get; set; }
//...
}
and want to dinamically filter a List of Contratos based on Contratos.entidadeFinanceira.Nome. This is part of a Method that filters the list based on a property selected by the user.
public IQueryable<Models.Contratos> applyLambdaFilter(string val, string col, string oper, IQueryable<Models.Contratos> contratosList)
{
if (!string.IsNullOrWhiteSpace(val))
{
string typeName;
string columnName;
Type propType;
string[] propName = col.Split(new[] { '.' });
if (propName.Count() > 1)
{
typeName = "GAcordos.Models." + propName[0]; //entidadeFinanceira
columnName = propName[1]; //Nome
propType = Type.GetType("GAcordos.Models.Contratos").GetProperty(propName[0]).PropertyType.GetProperty(columnName).PropertyType; //String
}
else
{
typeName = "GAcordos.Models.Contratos";
columnName = propName[0]; //Other Contratos property
propType = Type.GetType(typeName).GetProperty(columnName).PropertyType;
}
if (propType != null)
{
var fixedItem = Comparators.getFixedItemWithType(val, propType);
var param = Expression.Parameter(typeof(GAcordos.Models.Contratos), "x");
var body = Expression.Equal(Expression.PropertyOrField(param, col.ToString()), fixedItem, false, Type.GetType("GAcordos.Helpers.Comparators").GetMethod(oper, new Type[] { propType, propType }));
var lambda = Expression.Lambda<Func<GAcordos.Models.Contratos, bool>>(body, param);
contratosList = contratosList.Where(lambda.Compile()).AsQueryable();
}
}
return contratosList;
}
When the Method executes it throws an exception 'entidadeFinanceira.Nome' is not a member of type 'GAcordos.Models.Contratos' on the line
var body = Expression.Equal(Expression.PropertyOrField(param, col.ToString()), fixedItem, false, Type.GetType("GAcordos.Helpers.Comparators").GetMethod(oper, new Type[] { propType, propType }));
But if I write the expression directly:
contratosList = contratosList.Where(x => x.entidadeFinanceira.Nome == val);
it works fine.
So, how can I build the lambda expression x => x.property.property == constVal?
回答1:
Simply, you need two uses of PropertyOrField.
Constructed manually, x => x.Foo.Bar == constVal is:
var param = Expression.Parameter(typeof(ObjectType), "x");
var lambda = Expression.Lambda<Func<ObjectType, bool>>(
Expression.Equal(
Expression.PropertyOrField(
Expression.PropertyOrField(param, "Foo"), "Bar"
), Expression.Constant(constVal, constValType)
), param);
(note that it is important to include constValType in case constVal is null; this avoids a lot of unexpected problems)
回答2:
Seems that when calling
Expression.PropertyOrField(param, col.ToString())
the variable col contains "entidadeFinanceira.Nome". You may reuse all the splitting of col you did above and do something like:
Expression property = param;
foreach(var pName in propName) {
property = Expression.PropertyOrField(property, pName);
}
Now the expression property should be correct and you can use it to build the body expression:
var body = Expression.Equal(
property,
fixedItem,
false,
Type
.GetType("GAcordos.Helpers.Comparators")
.GetMethod(oper, new Type[] { propType, propType })
);
来源:https://stackoverflow.com/questions/6384500/lambda-expression-to-access-a-property-of-an-object-that-is-property-of-another