Search code examples
c#expressionexpression-treesrule-engineruntime-compilation

Variable '' of type 'System.Data.DataRow' referenced from scope '', but it is not defined


I am trying to build generic function to apply rules on DataRows.

But I am getting following error while running the programe

Here is my code.

public Func<T, bool> CompileRuleDataRow<T>(Rule r)
{
    var paramUser = Expression.Parameter(typeof(T));
    Expression expr = BuildExprDataRow<T>(r, paramUser);
    // build a lambda function User->bool and compile it
    //Expression.Lambda<Func<T, bool>>(
    return Expression.Lambda<Func<T, bool>>(expr, paramUser).Compile();
}

Function for building expression.

public Expression BuildExprDataRow<T>(Rule r, ParameterExpression param)
{
    ParameterExpression objExpr = Expression.Parameter(typeof(string));
    string defaultMember = "Item";
    ConstantExpression indexExpr = Expression.Constant(r.MemberName);
    Expression leftIndexAccessExpr = Expression.Property(objExpr, defaultMember, indexExpr);
    ExpressionType tBinary;
    // is the operator a known .NET operator?
    ExpressionType.TryParse(r.Operator, out tBinary);
    var right = Expression.Constant(r.TargetValue);
    // use a binary operation, e.g. 'Equal' -> 'u.Age == 15'
    return Expression.MakeBinary(tBinary, leftIndexAccessExpr, right);
}

and I am calling it in this way in main method.

var rule = new Rule("Name", "Equal", "3");
Func<DataRow, bool> compiledRuleDataRow = CompileRuleDataRow<DataRow>(rule);
DataTable dt = new DataTable();
dt.Columns.Add("Id");
dt.Columns.Add("Name");
dt.Columns.Add("Address");
for (int i = 0; i < 100000; i++)
{
  dt.Rows.Add(i.ToString(), i.ToString(), i.ToString());
}
//I want to do something like this.
    DataRow[] drFiltered = dt.Select().Where(r => compiledRuleDataRow(r)).ToArray();

And below is my Rule class

public class Rule
{
  public string MemberName { get; set; }
  public string Operator { get; set; }
  public string TargetValue { get; set; }

  public Rule(string MemberName, string Operator, string TargetValue)
  {
    this.MemberName = MemberName;
    this.Operator = Operator;
    this.TargetValue = TargetValue;
  }
}

When I run this code I am getting following error.

variable '' of type 'System.Data.DataRow' referenced from scope '', but it is not defined

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.InvalidOperationException: variable '' of type 'System.Data.DataRow' referenced from scope '', but it is not defined

Can somebody please help me out?


Solution

  • Like @svick, I'm getting a different error from the posted code.

    Anyway, there are two problems with that BuildExprDataRow method. First, it's not using the passed param argument. Second, the property value is not properly converted, so the binary operators does not work.

    Here is the fixed method:

    public Expression BuildExprDataRow<T>(Rule r, ParameterExpression param)
    {
        var right = Expression.Constant(r.TargetValue);
        var left = Expression.Convert(
            Expression.Property(param, "Item", Expression.Constant(r.MemberName)),
            right.Type);
        var comparison = (ExpressionType)Enum.Parse(typeof(ExpressionType), r.Operator);
        return Expression.MakeBinary(comparison, left, right);
    }
    

    Btw, the generic argument T is not used either inside that method, so you can remove it (make the method non generic).