Sophisticated builder methods with Expression trees - c#

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.

Related

Equivalent of Delegate.Target for LambdaExpression

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.)

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.

Pass method name from property to lambda without arguments

I am trying to achieve the following:
this.helper.Verify(i => i.SomeModule.SomeMethod);
Where:
i is a known type.
SomeModule is a public property of this type.
SomeMethod is the name of the method (passed as delegate I assume).
I would like to be able to avoid specifying the generic types in the Verify method.
Thats how far I've been able to go:
public void Verify<TProp, TResult>(
Expression<Func<KnownType, TProp>> moduleExpression,
Expression<Func<TProp, TResult>> methodExpression)
{
var moduleIdentifier = (moduleExpression.Body as MemberExpression).Member.Name;
var methodIdentifier = (methodExpression.Body as MethodCallExpression).Method.Name;
this.Verify(moduleIdentifier, methodIdentifier, state);
}
But this forces me to write the argument values for the methodExpression, like:
this.helper.Verify(
i => i.SomeModule,
m => m.SomeMethod(arg1, arg2));
Is there a way to achieve what I am looking for?
Finally I end up with a solution that requires delegates.
I need to analyze an expression that can have multiple arguments, like:
i => i.Car.Engine.Intake.Open()
I will extract the last two arguments as a "module" and "method":
public class ExpressionTools
{
public string GetLastInstanceName<TProp, TDelegate>(Expression<Func<TProp, TDelegate>> expression)
{
var unaryExpression = (UnaryExpression)expression.Body;
var methodCallExpression = (MethodCallExpression)unaryExpression.Operand;
var methodInfoExpression = (MemberExpression)methodCallExpression.Arguments.Reverse().Skip(1).First();
var instanceName = methodInfoExpression.Member.Name;
return instanceName;
}
public string GetMethodName<TProp, TDelegate>(Expression<Func<TProp, TDelegate>> expression)
{
var unaryExpression = (UnaryExpression)expression.Body;
var methodCallExpression = (MethodCallExpression)unaryExpression.Operand;
var methodInfoExpression = (ConstantExpression)methodCallExpression.Arguments.Last();
var methodInfo = (MemberInfo)methodInfoExpression.Value;
return methodInfo.Name;
}
}
Solution with delegates
A class with generics can be reused since the delegates are not necessary to analyze the expression:
public class Verifier
{
public void Verify<TDelegate>(Expression<Func<KnownType, TDelegate>> methodExpression)
{
var tools = new ExpressionTools();
var moduleName = tools.GetLastInstanceName(methodExpression);
var methodName = tools.GetMethodName(methodExpression);
// My logic.
}
}
Now I need to create the delegates, For that I created a file and declared them without a class:
namespace Whatever
{
public delegate void VoidDelegate();
public delegate void VoidBoolDelegate(bool value);
// etc...
}
Finally, I need to maintain a class that has the same method overloaded with the different delegates.
public class FakeExtensions
{
public static void Verify(
this Fake fake,
Expression<Func<KnownType, VoidDelegate>> methodExpression)
{
var tools = new ExpressionTools();
var facilitator = new Verifier(fake, tools);
facilitator.Verify(methodExpression);
}
public static void Verify(
this Fake fake,
Expression<Func<KnownType, VoidBoolDelegate>> methodExpression)
{
var tools = new ExpressionTools();
var facilitator = new Verifier(fake, tools);
facilitator.Verify(methodExpression);
}
}
Alternative solution without delegates
The easiest solution would be to pass a default value for each parameter, but that would express that the values are also verified, which is not the case. I really dislike the idea of having something like this:
this.helper.Verify(i => i.SomeModule.SomeMethod(0, false, 0.0, null);
Since Moq is part of our testing framework, it is possible to use It.IsAny as a value for each parameter of a method call, wich expresses that the values don't matter:
this.helper.Verify(i => i.SomeModule.SomeMethod(It.IsAny<int>, It.IsAny<bool>, It.IsAny<double>, It.IsAny<SomeType>);
Why did I choose the delegates solution
I have to verify some calls on a low-level 3rd party API that has methods with up to 100 parameters. I think that the burden of maintaining a delegates list and method overloads pays off in maintainability, readability and ease of use.

Multiple Groupby keySelectors using Linq Expressions

I have a list of objects which need to be grouped by a set of properties. These set of properties would be known only at runtime . I would like to accomplish this without using Dynamic LINQ. Following code from Dynamically Adding a GroupBy to a Lambda Expression by Kirk Woll works fine, but this groups the result by one property.
public static IQueryable<IGrouping<TColumn, T>> DynamicGroupBy<T, TColumn>(IQueryable<T> source, string column)
{
PropertyInfo columnProperty = typeof(T).GetProperty(column);
var sourceParm = Expression.Parameter(typeof(T), "x");
var propertyReference = Expression.Property(sourceParm, columnProperty);
var groupBySelector = Expression.Lambda<Func<T, TColumn>>(propertyReference, sourceParm);
return source.GroupBy(groupBySelector);
}
I would like to pass a list of columnNames and be able to groupby multiple keySelectors. I am not sure how to accomplish this. Please help.
It seems like if we could dynamically generate the equivalent of the expression:
x => new { a = x.Prop1, b = x.Prop2, ... }
Then a reasonable LINQ => SQL provider would probably generate the SQL you want. Generating a new anonymous type on the fly seems hard, but we could take advantage of the fact that anonymous types are generic to re-use one.
// at the top of your class
private static readonly object AnonymousObjectWithLotsOfProperties = new {
a = 1,
b = 2,
...
};
// then in your method
// (1) first get the list of properties represented by the string you passed in (I assume you know how to do this via reflection)
var props = typeof(T).GetProperties().Where(...);
var propTypes = props.Select(pi => pi.PropertyType).ToList();
// (2) now generate the correctly genericized anonymous type to use
var genericTupleType = AnonymousObjectWithLotsOfProperties.GetType()
.GetGenericTypeDefinition();
// for generic args, use the prop types and pad with int
var genericArguments = propTypes.Concat(Enumerable.Repeat(typeof(int), genericTupleType.GetProperties().Length - propTypes.Count))
.ToArray();
var tupleType = genericTupleType.MakeGenericType(genericArguments);
// (3) now we have to generate the x => new { ... } expression
// if you inspect "System.Linq.Expressions.Expression<Func<object>> exp = () => new { a = 2, b = 3 };"
// in the VS debugger, you can see that this is actually a call to a constructor
// on the anonymous type with 1 argument per property
var tParameter = Expression.Parameter(typeof(T));
// create the expression
var newExpression = Expression.New(
constructor: tupleType.GetConstructors().Single(), // get the one constructor we need
// the arguments are member accesses on the parameter of type T, padded with 0
arguments: props.Select(pi => Expression.MakeMemberAccess(tParameter, pi))
.Concat(Enumerable.Repeat(Expression.Constant(0), genericTupleType.GetProperties().Length - propTypes.Count))
);
// create the lambda: we need an Expression<TDelegate>, which means that we
// need to get the generic factory method from Expression and invoke it
var lambdaGenericMethod = typeof(Expression).GetMethods(BindingFlags.Static | BindingFlags.Public)
.Single(m => m.IsGenericMethodDefinition);
var lambdaMethod = lambdaGenericMethod.MakeGenericMethod(typeof(Func<,>).MakeGenericType(typeof(T), tupleType));
// reflection for Expression.Lambda(body, parameters)
var lambda = lambdaGenericMethod.Invoke(null, new object[] { newExpression, new[] { tParameter });
// now that we have the expression, we can invoke GroupBy via reflection.
// Of course, that leaves you with an IQueryable<IGrouping<ANON, T>>, which isn't much
// use until you apply some other IQueryable methods to eliminate the ANON type from the
// method signature so you can return it
Note that I didn't actually get to compile and run this code, so I can't promise that everything above is perfect. However, hopefully it will put you on the right track.
What's wrong with this:
Group By Multiple Columns
Here's an example using the .GroupBy method rather than the Linq:
public class Program
{
static void Main(string[] args)
{
var list = new List<SomeType>
{
new SomeType("Mr", "Joe", "Bloggs"),
new SomeType("Mr", "John", "Citizen"),
new SomeType("Mrs", "Mary", "Mac")
};
var list2 = list.GroupBy(by => new { by.Property1, by.Property2 });
}
}
public class SomeType
{
public string Property1 { get; private set; }
public string Property2 { get; private set; }
public string Property3 { get; private set; }
public SomeType(string property1, string property2, string property3)
{
Property1 = property1;
Property2 = property2;
Property3 = property3;
}
}

Using Implicit Type Syntax on Method Return

Not exactly how sure how to title this question, so I hope the title works.
The question is, can I use something similar to implicit type syntax on method calls. For example, this is the implicit type syntax I am referring to:
var x = new Y(){Foo = "Bar", Id = 1};
And I want to do something like this:
var x = myInstance.CreateItem(){Foo = "Bar", Id = 1};
Is there anything in C# that supports something like this? I don't want to do:
x.Foo = "Bar";
x.Id = 1;
...
Please note that CreateItem returns a dynamic type. The CreateItem method and its class cannot be modified.
I would settle for something similar to the With statement in VB.
Thanks in advance.
UPDATE: Attempting Mark Brackett's solution yielded this code:
TaskItem item = outlook.CreateItem(OlItemType.olTaskItem)._((Action<dynamic>)(i =>
{
i.Subject = "New Task";
i.StartDate = DateTime.Now;
i.DueDate = DateTime.Now.AddDays(1);
i.ReminderSet = false;
i.Categories = "#Work";
i.Sensitivity = OlSensitivity.olPrivate;
i.Display = true;
}));
...
public static class Extension
{
public static T _<T>(this T o, System.Action<dynamic> initialize) where T : class
{
initialize(o);
return o;
}
}
The only problem now is that the extension method doesn't seem to be binding to System._ComObject because I get this error: System._ComObject' does not contain a definition for '_'.
It's called an "object initializer", and no - it's not available for return values (or really, anytime other than with a new statement).
Syntax wise, about the closest I can think of would be to use an Action delegate (which requires changes to the Builder):
MyItem CreateItem(Action<MyItem> afterCreate) {
var i = new MyItem();
if (afterCreate != null) afterCreate(i);
return i;
}
var x = Builder.CreateItem(i => { i.Foo = "Bar"; i.Id = 1; });
If you're in a JavaScripty mood for short method names for commonly used functions, and can't change the Builder, I guess an extension method would also work:
public static T _<T>(this T o, Action<T> initialize) where T : class {
initialize(o);
return o;
}
var x = Builder.CreateItem()._(i => { i.Foo = "Bar"; i.Id = 1; });
Here's a twist for you. CreateItem() returns a dynamic type
Contrary to my comment, dynamic does require a few changes. You need to cast to object or the lambda will complain, and then you need to specify dynamic as T or it'll be inferred as object. Or, create your extension method with Action<dynamic> and no type arguments.
object CreateItem() {
return (object)Builder.CreateItem();
}
public static dynamic __(this object o, Action<dynamic> initialize) {
initialize(o);
return o;
}
var x = CreateItem().__(i => { i.Foo = "Bar"; i.Id = 1; });
You could use named arguments to the factory method:
public static Y Builder.CreateItem(string foo = "", int bar = 0)
{
return new Y() {Foo = foo, Bar = bar};
}
// called like so:
var x = Builder.CreateItem(Foo: "Bar", Id: 1);
You can specify 'public properties' in the constructor of the class but you cannot do that with methods
because
This rules only apply to member properties which is not possible with methods
You can not give public modofier in fields in the method so there is no possibility atall
When you do
var a = new MyClass{Foo="",Id=""};
You are defining properties of the class of this constructor MyClass()
You cannot do that with static or instance method

Categories