60

I have a Func<TCollection, T> in my code. I use it to select certain properties.

In a call to another method I need Expression<Func<TCollection, T>> as a parameter.

Is there any way to convert (or create from) Func<TCollection, T> to Expression<Func<TCollection, T>> ?

Thanx

SolarX
  • 1,873
  • 2
  • 18
  • 26
  • 1
    Possible duplicate of [converting a .net Func to a .net Expression>](https://stackoverflow.com/questions/767733/converting-a-net-funct-to-a-net-expressionfunct) – GSerg Feb 26 '19 at 14:42

5 Answers5

64

You can not recreate an expression based on a method since an expression needs to know the original statements, not IL. You can however create an Expresson which makes a method call to your func like:

Func<int> func = () => 1;
Expression<Func<int>> expression = Expression.Lambda<Func<int>>(Expression.Call(func.Method));

Note however that systems like EF can't really work with this

Polity
  • 14,734
  • 2
  • 40
  • 40
  • 2
    Assuming you *could* get the IL, though, you could decompile the IL, as Reflector and ILSpy do. (Of course, there's no guarantee that this would be exactly the same as the code from which the IL was compiled.) Is there a way to get at the IL of a delegate? – phoog Feb 21 '12 at 14:37
  • 6
    I think you might need to add the func.Target in your call. I tried this with a more complex Func<> and it complained I was trying to call an instance method with a null object. I changed it to Expression.Call(Expression.Constant(func.Target), func.Method, args) and all was fine – ben Mar 13 '14 at 16:35
  • EF can work with it if cooked right. see https://stackoverflow.com/a/40958545/292787 – Stanislav Mar 04 '21 at 09:07
39

While you could just create an expression tree which calls your delegate, it's unlikely to be useful - because the delegate will basically be a black box as far as the code analyzing the expression tree is concerned. Assuming you're trying to use something like LINQ to SQL, the query analyzer will need to be able to peer into your logic to convert it to SQL - and it can't do that if it reaches a plain delegate.

You should probably change the code which comes up with the delegate in the first place, to create an expression tree instead.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
34

You can do something like this:

Func<object, string> func = a => a.ToString();
Expression<Func<object, string>> expr = a => func(a);

But you will only get an expression containing your method call to the original Func. You won't be able to analyse the contains of the func itself.

Simon
  • 5,373
  • 1
  • 34
  • 46
  • 4
    But naturally Mr Skeet puts it much better than me! :-) – Simon Feb 21 '12 at 12:36
  • 3
    you say that, but your answer is the the one that made sense to me the morning after the night spent hooning to and from the airport.... Quite succinctly restates the idea that a func is something that can be called, and an expression is a call to a func. – Grimm The Opiner Jul 18 '18 at 07:31
9

You cannot create an expression from a delegate (from Func<TCollection, T> to Expression<Func<TCollection, T>>) but you can do the oposite.

That is, convert a Expression<Func<TCollection, T>> to a Func<TCollection, T> by compiling it (.compile).

So, if you need both of them you can use expressions at your functions and in case you need it, compile and execute them on a provided collection object.

We have to note of course that compiling an expression is slow.

George Mavritsakis
  • 6,829
  • 2
  • 35
  • 42
1

Create a class like below;

 public class GenericFilter<T> where T : class, new()
    {
        public Expression<Func<T, bool>> Filter = item => true;

    }

Usage;

var filter=new GenericFilter<blabla>().Filter.And(x=>...);
filter=filter.And(x=>...);
F.Çetin
  • 11
  • 1