0

This lambda does not compile, but I do not understand why.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using LinqKit;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
    {
        var barModel = new BarModel();
        string id = "some";

        Console.WriteLine(barModel.subFor(id).ToString());
            // output: m => (True AndAlso (m.key == value(ConsoleApplication2.Bar`1+<>c__DisplayClass0[ConsoleApplication2.Model]).id))
        Console.ReadKey();


        var subworkitems = barModel.list.Where(barModel.subFor(id).Compile());
                // Exception {"variable 'm' of type 'ConsoleApplication2.Model' referenced from scope '', but it is not defined"}

        Console.WriteLine(subworkitems.ToString());
        Console.ReadKey();
    }
}

class Bar<TModel>
{

    public Bar(Expression<Func<TModel, string>> foreignKeyExpression)
    {
        _foreignKeyExpression = foreignKeyExpression;
    }

    private Expression<Func<TModel, string>> _foreignKeyExpression { get; set; }

    public Expression<Func<TModel, bool>> subFor(string id)
    {

        var ex = forTargetId(id);

        return ex;
    }

    public Expression<Func<TModel, bool>> forTargetId(String id)
    {

        var fc = _foreignKeyExpression;

        Expression<Func<TModel, bool>> predicate = m => true;

        var result = predicate.And(m => fc.Invoke(m) == id).Expand();

        return result;

    }

}

class Model
{
    public string key;
    public string value;
}

class BarModel : Bar<Model>
{
    public List<Model> list;

    public BarModel() : base(m => m.key) 
    {
        list = new List<Model>();
    }
}


}
1
  • 1
    Can you supply the error details? Commented Apr 21, 2010 at 22:30

1 Answer 1

2

Solution 1

This solution doesn't strip out the invoke statements which I assume you are trying to do by calling "Expand".

change the result of "forTargetId(String id)" to

predicate.And(m => fc.Invoke(m) == id);

When the expression is compiled in the where clause it will know that it needs to pass "m" to the fc expression above.

My first tip came when I changed

predicate.And(m => fc.Invoke(m) == id).Expand();

to

predicate.And(n => fc.Invoke(n) == id).Expand();

and I could see that n was not being pass along at all.

I tested out this change by manipulating the Main method as follows

static void Main(string[] args)
{
    var barModel = new BarModel();
    barModel.list.Add(new Model() { key = "1", value = "One" });
    barModel.list.Add(new Model() { key = "2", value = "Two" });
    barModel.list.Add(new Model() { key = "some", value = "Three" });

    string id = "some";

    Console.WriteLine(barModel.subFor(id).ToString());
    // output: m => (True AndAlso (m.key == value(ConsoleApplication2.Bar`1+<>c__DisplayClass0[ConsoleApplication2.Model]).id))
    Console.ReadKey();


    var subworkitems = barModel.list.Where(barModel.subFor(id).Compile());
    // Exception {"variable 'm' of type 'ConsoleApplication2.Model' referenced from scope '', but it is not defined"}

    foreach (var si in subworkitems)
    {
        Console.WriteLine(si.key);
        Console.WriteLine(si.value);
    }

    Console.WriteLine(subworkitems.ToString());
    Console.ReadKey();
}

Solution 2

This solution does remove the Invoke statements with the use of the Expand method but changes the way that you are anding the statements together.

The "Expand" function is advertised as following on the LinqKit website.

Expression<Func<Purchase, bool>> criteria1 = p => p.Price > 1000;
Expression<Func<Purchase, bool>> criteria2 = p => criteria1.Invoke(p) || p.Description.Contains("a");
Console.WriteLine(criteria2.Expand().ToString());
// p => ((p.Price > 1000) || p.Description.Contains("a"))

Notice that they aren't using the "And" method to put these things together but instead they are "daisy chaining" the calls together.

Instead of

Expression<Func<TModel, bool>> predicate = m => true;
var result = predicate.And(m => fc.Invoke(m) == id).Expand();

Do this

Expression<Func<TModel, bool>> predicate = m => fc.Invoke(m) == id && true;
return predicate.Expand();
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.