Equivalent of Delegate.Target for LambdaExpression - c#

Given the following class:
public class Foo {
public string Bar {get; set;}
Func<string> GetFunc = () => Bar;
}
the following code will print True:
var foo = new Foo();
var fn = foo.GetFunc;
Console.WriteLine(fn.Target == foo);
because the target of the action delegate is the instance of the object.
How can I get a hold of an expression that represents the target of a LambdaExpression returned by an instance?
public class Foo1 {
public string Bar {get;set;}
Expression<Func<string>> GetExpression = () => Bar;
}
var foo = new Foo();
var expr = foo.GetExpression;
// ???
I thought compiling expr and checking the Target property of the generated delegate would work, and it does return an instance of Closure, where foo is one of the objects referred to by the array at the Constants property.
var closure = expr.Compile().Target as System.Runtime.CompilerServices.Closure;
Console.WriteLine(closure.Constants.Contains(foo));
// prints True
However, this doesn't help me, because if I construct the expression using the factory methods at System.Linq.Expressions.Expression, and specify an external instance as a Constant within the expression tree:
// using static System.Linq.Expressions.Expression;
var foo = new Foo();
Expression<Func<string>> expr = Lambda<Func<string>>(
MakeMemberAccess(
Constant(foo),
typeof(Foo).GetMember("Bar").Single()
)
);
the external instance (foo in this case) will also be included in the Constants.
I am looking specifically for the object (or objects) referred to by this in a compiler-generated LambdaExpression (and if there are no conflicts with other identifiers, the this can be elided).
(Some background can be found here.)

Related

How to groupBy with compiled lambda function with type generated during runtime

I have a compiledLambda function that runs against an interface. Unfortunately the interface is just a marker interface and the real type is generated on the fly during runtime and has properties I want to do a grouping on.
Here's some sample code:
class Program
{
static void Main(string[] args)
{
// Just an example assignment: In the real life scenario the dynamic generated class is created during runtime.
IEnumerable<IDynamicGeneratedModelClass> list = GetDataFromService();
// get the 'real' type from the list
LambdaExpression lambdaExpression = DynamicExpression.ParseLambda(list.First().GetType(), typeof(object), "SomeProperty");
Func<IDynamicGeneratedModelClass, object> compiledLambdaFunction = (Func<IDynamicGeneratedModelClass, object>)lambdaExpression.Compile();
// Expected result: Group list on "SomeProp"
var result = list.GroupBy(compiledLambdaFunction);
}
private static IList<IDynamicGeneratedModelClass> GetDataFromService()
{
return new List<IDynamicGeneratedModelClass> {
new DynamicGeneratedModelClass("Class1"),
new DynamicGeneratedModelClass("Class2")
};
}
}
public interface IDynamicGeneratedModelClass
{}
public class DynamicGeneratedModelClass : IDynamicGeneratedModelClass
{
public DynamicGeneratedModelClass(string someProperty)
{
SomeProperty = someProperty;
}
public string SomeProperty { get; }
}
When the the lambda expression is compiled it throws the following exception:
System.InvalidCastException: 'Unable to cast object of type
'System.Func`2[ConsoleApp12.DynamicGeneratedModelClass,System.Object]'
to type
'System.Func`2[ConsoleApp12.IDynamicGeneratedModelClass,System.Object]'.'
Could you please give me a hint what I am doing wrong and how to fix it ?
The first generic parameter of the Func<T, TResult> delegate is declared as contravariant (in), which means that you can assign delegate with less derived parameter to delegate with more derived parameter, but not vice versa (in another words, you can cast Func<IDynamicGeneratedModelClass,Object> to Func<DynamicGeneratedModelClass,Object>, but cannot cast Func<DynamicGeneratedModelClass,Object> to Func<IDynamicGeneratedModelClass,Object>).
To avoid this problem, instead of lambda expression you generate now:
// lambda has "wrong" type Func<DynamicGeneratedModelClass, object>
(DynamicGeneratedModelClass item) => item.SomeProperty
generate lambda equivalent to this:
// lambda now has "correct" type Func<IDynamicGeneratedModelClass, object>
(IDynamicGeneratedModelClass item) => ((DynamicGeneratedModelClass)item).SomeProperty
I'm not familiar with the DynamicExpression library you used to generate you lambda, but this can be easily done using just System.Linq.Expression classes:
var itemType = list.First().GetType();
var propertyName = "SomeProperty";
var parameterExpr = Expression.Parameter(typeof(IDynamicGeneratedModelClass));
var castExpr = Expression.Convert(parameterExpr, itemType);
var propExpr = Expression.Property(castExpr, propertyName);
var lambdaExpr = Expression.Lambda(propExpr, parameterExpr);
// Compiled lambda is now of type Func<IDynamicGeneratedModelClass, object>
Func<IDynamicGeneratedModelClass, object> compiledLambdaFunction = (Func<IDynamicGeneratedModelClass, object>)lambdaExpr.Compile();
var result = list.GroupBy(compiledLambdaFunction);

Use value of property expression inside expression tree

Consider a property expression like t => t.MyProperty where t is of type MyClass. How can I use this property expression inside a new expression where I perform a method call?
Pure C#:
class MyClass
{
public string MyProperty { get; set; }
}
static void Foo(string foo)
{
}
LambdaExpression GetExpression(Expression<Func<MyClass, object>> expr)
{
return expr;
}
var myClass = new MyClass();
Foo(myClass.MyProperty);
Now with expressions...?
var expr = GetExpression(m => m.MyProperty);
var mi = typeof(Program).GetMethod(nameof(Program.Foo),
BindingFlags.Public | BindingFlags.Static);
var myClass = new MyClass();
// Now what??
// var call = Expression.Call(mi, ???expr??);
// var invoke = Expression.Invoke(call, fooParameter);
I want to use the result of expr and use that in the call to Foo. I know I can do this in two steps, where I call expr.Compile().DynamicInvoke(myClass) to get the value, but that is not what I'm asking for here.
I want to build an expression that takes a property getter expression and then performs a call to Foo(result of expression). I cannot figure out how to use the expression as a parameter to the method call.
There's two ways of doing this, depending on the complexity. In this case, we can re-use the parameter from the inner expression - bubbling it outwards; we do this by discarding our old lambda, just using the .Body and .Parameters. For example:
var call = Expression.Lambda<Action<MyClass>>(
Expression.Call(mi, expr.Body), expr.Parameters);
var myClass = new MyClass { MyProperty = "yay!" };
call.Compile().Invoke(myClass);
The other way is to use Invoke on the inner lambda:
var outerParameter = Expression.Parameter(typeof(MyClass));
var typed = Expression.Convert(Expression.Invoke(expr, outerParameter), typeof(string));
var call = Expression.Lambda<Action<MyClass>>(Expression.Call(mi, typed), outerParameter);
The second form (Invoke) is useful when you can't conveniently control the parameters in the two places - or where, for example, you have multiple inner expressions with different parameter instances.

Get Attribute from Function<T>

How I can get a custom attribute from a Function object?
public static void Main(string[] args) {
Func<object> fun = () => Foo();
//fun. Get Foo Custom Attribute
}
[CustomAttrib]
public static object Foo() {
return new object();
}
With a Function, the information you're looking for is not available AFAIK.
However, if it were an Expression, it would be quite easy:
Expression<Func<object>> expression = () => Foo();
var method = ((MethodCallExpression)expression.Body).Method;
Console.WriteLine(method.GetCustomAttributes(false)[0]);
You can convert an Expression to a Function with the Compile() method.
var fun = expression.Compile();
This might be helpful if you define the Function yourself, but not if comes from some 3rd party code which you can't modify.

Sophisticated builder methods with Expression trees

Let's say I've to create the following method in runtime
Type someType = ...; // assigned somewhere
var method = (presenter) =>
{
var instance = new SomeType(); // I've only default constructor here
instance.SomeProperty = presenter;
return instance;
}
Does anybody know how can I create such method in runtime using Expression trees?
The key here is to use Expression.Block to get the multi statement lambda. You can use something like:
void Main()
{
var p = Expression.Parameter(typeof(int), "presenter");
var instance = Expression.Variable(typeof(Foo), "instance");
var ctor = typeof(Foo).GetConstructor(new Type[0]);
var block = Expression.Block(new [] { instance },
Expression.Assign(instance, Expression.New(ctor)),
Expression.Assign(Expression.Property(instance, "SomeProperty"), p),
instance
);
var lambda = Expression.Lambda<Func<int,Foo>>(block, p);
Foo f = lambda.Compile()(5);
Console.WriteLine(f.SomeProperty);
}
class Foo
{
public int SomeProperty {get;set;}
}
Of course you need to tweak this to fit your needs, which parts are variable and which are not, and so on, but it demonstrates the general idea.

Expression tree - how to get at declaring instance?

I'm a newbie when it comes to expression trees, so I'm not sure how to ask this question or what terminology to use. Here's an overly-simplifed version of what I'm trying to do:
Bar bar = new Bar();
Zap(() => bar.Foo);
public static void Zap<T>(Expression<Func<T>> source)
{
// HELP HERE:
// I want to get the bar instance and call bar.Zim() or some other method.
}
How can I get to bar inside the Zap method?
Since the expression passed into your Zap method is a tree, you just need to walk the tree using an Expression Tree Visitor and look for the first ConstantExpression in the expression. It will likely be in the following sequence:
(((source.Body as MemberExpression).Expression as MemberExpression).Expression as ConstantExpression).Value
Note that the bar instance is captured by a closure, which is implemented as an internal class with the instance as a member, which is where the 2nd MemberExpression comes from.
EDIT
Then you have to get the field from the generated closure like so:
static void Main(string[] args)
{
var bar = new Bar();
bar.Foo = "Hello, Zap";
Zap(() => bar.Foo);
}
private class Bar
{
public String Foo { get; set; }
}
public static void Zap<T>(Expression<Func<T>> source)
{
var param = (((source.Body as MemberExpression).Expression as MemberExpression).Expression as ConstantExpression).Value;
var type = param.GetType();
// Note that the C# compiler creates the field of the closure class
// with the name of local variable that was captured in Main()
var field = type.GetField("bar");
var bar = field.GetValue(param) as Bar;
Debug.Assert(bar != null);
Console.WriteLine(bar.Foo);
}
If you know the type of "bar", you can do this (I'm reusing some bits from the codekaizen's answer here):
static void Main(string[] args)
{
var bar = new Bar();
bar.Foo = "Hello, Zap";
Zap(() => bar.Foo);
Console.ReadLine();
}
private class Bar
{
public String Foo { get; set; }
}
public static void Zap<T>(Expression<Func<T>> source)
{
var body = source.Body as MemberExpression;
Bar test = Expression.Lambda<Func<Bar>>(body.Expression).Compile()();
Console.WriteLine(test.Foo);
}
In most cases, you can find an expression representing your object within an expression tree, and then compile and execute this expression and get the object (but this is not a very fast operation, by the way). So, the bit you were missing is the Compile() method. You can find a little bit more info here: How to: Execute Expression Trees.
In this code, I assume that you always pass an expression like "() => object.Member". For a real-world scenario you will need either to analyze that you have an expression you need (e.g. just throw an exception if it's not a MemberExpression). Or use ExpressionVisitor, which is kind of tricky.
I have recently answered a very similar question here:
How do I subscribe to an event of an object inside an expression tree?
Standing on the shoulders of giants above, my final extension method to extract the instance of the class that represented the source of the expression looks as follows:
public static TIn GetSource<TIn, TOut>(this Expression<Func<TIn, TOut>> property)
where TIn: class
{
MemberExpression memberExpression = (MemberExpression)property.Body;
TIn instance = Expression.Lambda<Func<TIn>>(memberExpression.Expression).Compile()();
return instance;
}
I built on all of the answers above, thanks to all.

Categories