Pass Expression Tree as Method parameter - c#

I have a function:
public void Execute(Expression<Action> expression)
{
var time = expression.Compile().Benchmark();
var msg = string.Format("{0} took {1} to complete",
ReflectionHelper.GetComponentCallDetails().ToString(),
time.ToString(#"hh\:mm\:ss\.ff"));
Logger.Info(msg);
}
The delegate that needs to be called is something like:
channels = GetAllChannelsImpl(maxResults);
I am relatively new to Expression Trees and cannot figure out a way to pass the Action delegate to the method.
I was able to do the same functionality using
public void Execute(Action action)
{
var time = action.Benchmark();
var msg = string.Format("{0} took {1} to complete",
ReflectionHelper.GetComponentCallDetails().ToString(),
time.ToString(#"hh\:mm\:ss\.ff"));
Logger.Info(msg);
}
and calling as
Execute(() =>
{
channels = GetAllChannelsImpl(maxResults);
});
But I wanted to use the Expression Tree based approach in order to eliminate the need to use the overhead of reflection to figure out the details of the method invoked to log it.
Can anyone suggest the right way to pass the expression tree for the above action delegate as a method parameter.

A lambda expression by itself does not have a type. The actual type it takes is inferred by the compiler depending on what you are trying to assign or cast to. With that said, any calls to your Execute() method using simple lambdas will be ambiguous since your lambda would be compatible as an Action or Expression<Action>. You would have to disambiguate this by explicitly casting to the type you expect.
// assign to a variable
Expression<Action> action1 = () => ...;
Execute(action1);
// cast
Execute((Expression<Action>)(() => ...));
// use the constructor
Execute(new Expression<Action>(() => ...));
It would be better IMHO to remove the ambiguous overload and rename one of the methods. I'd recommend renaming the expression overload to ExecuteExpression().

Related

Create lambda action delegate dynamically

Can I create an Action delegate with a lambda expression like this () => Method(args) dynamically when I have the target, MethodInfo and arguments to pass in?
Say I had a method that took an int argument and wanted to assign an Action delegate to call it with the argument 1 like so Action action = () => Method(1), but I want to do it dynamically. You could make a delegate and assign the action to dynamically invoke it, or assign it to invoke the method, but the performance is terrible.
public class DelegateData
{
public object target;
public MethodInfo method;
public object[] args;
}
Figured it out. It's quite easy with expressions, creating the delegate this way is of course incredibly slow (almost 1 second for 10.000 iterations), but afterward, the delegate is only twice as slow as it would be when created naturally. lambda.Compile is the culprit here, but I see no way around it.
var arguments = args.Select(a => Expression.Constant(a)).ToArray();
var lambda = Expression.Lambda(Expression.Call(Expression.Constant(target), method, arguments));
var result = (Action)lambda.Compile();

Get custom attribute of method executed in action

Here is my example metod
[TestStep("Do something")]
private void DoSomething()
{
}
Each method which looks like the one above is executed in a way which requires logging the method parameters:
private void LogStep(Action action)
{
string stepName = "[" + action.Method.Name + "] ";
var descr = Attribute.GetCustomAttribute(action.Method, typeof(TestStepAttribute)) as TestStepAttribute;
if (descr == null)
{
this.TestLog.AddWarningMessage(
(action.Method.DeclaringType == null ? string.Empty : action.Method.DeclaringType.FullName + ".") + action.Method.Name
+ ": missing description");
return;
}
stepName += descr.Description;
this.TestLog.EndGroup();
this.TestLog.BeginGroup(stepName);
}
And here I come with a problem. Executing LogStep like
LogStep(DoSomething)
works perfectly, but when I execute it using lambda expression
LogStep(() => DoSomething())
It tells me that there are no attributes of type TestStepAttribute in that Action.
At first glance it seems to be similar to How do I get the custom attributes of a method from Action<T>? but in my case I neither can change type of Action to Expression<Action> nor I know the method name.
Any suggestion'd be helpful.
When you execute it using a lambda expression, the lambda expression itself is the method. It happens that in its body there is a method call, but there could be something else there (like new object()). The only way to get access to the attributes of this inner method is to pass the lambda expression as Expression and to analyze the expression.
In order to handle both cases you will need two overloads of LogStep. However, you cannot have LogStep(Action) and LogStep(Expression<Action>) as overloads at the same time as the calls would be ambiguous. But it would work if one of them was LogStep(Delegate).
private void LogStep(Delegate action)
{
var attr = (TestStepAttribute)Attribute
.GetCustomAttribute(action.Method, typeof(TestStepAttribute));
Console.WriteLine("LogStep(Delegate action): " + attr?.Description);
}
private void LogStep(Expression<Action> actionExpr)
{
string descr = null;
var methodCall = actionExpr.Body as MethodCallExpression;
if (methodCall != null) {
var attribs = methodCall.Method.GetCustomAttributes(typeof(TestStepAttribute), true);
if (attribs.Length > 0) {
descr = ((TestStepAttribute)attribs[0]).Description;
}
}
Console.WriteLine("LogStep(Expression<Action> actionExpr): " + descr);
}
Tests:
LogStep(new Action(DoSomething)); // new Action() Is required here. Calls first overlaod.
LogStep(() => DoSomething()); // Calls second overload.
LogStep(() => new object()); // Calls second overload.
Note that you can compile and execute lambda expressions, in case you need to execute the method.
works perfectly, but when I execute it using lambda expression
LogStep(() => DoSomething()) It tells me that there are no attributes
of type TestStepAttribute in that Action.
Well of course won't find any attributes because you are passing a lambda expression which is basically a method and in that method you pass your method DoSomething() and the check is done on the lambda expression.
Lambda expression is just another method. When you look at action.Method, that's the method you get (and action.Target will contain a closure, if any).
In the end, all you have is:
void SomeAnonymousMethod()
{
DoSomething();
}
To get to the method actually being called, you'd have to decompile the anonymous method first. And of course, you're probably using the lambda syntax to pass arguments while still working with a paremeter-less action, where it gets even crazier:
class SomeClosure
{
string argument1;
int argument2;
void AnonymousMethod()
{
var data = GetSomeData(argument2);
DoSomething(data, argument1);
}
}
How do you even tell that DoSomething is the method you need metadata of?
There isn't a way around this using lambda expressions. Fortunately, it doesn't seem you actually need that anyway, since you're never calling the argument. Instead of using Action, just use Delegate, and you can pass whatever method you need directly:
void DoSomething(string something, string otherThing)
{
... // Not important
}
void LogStep(Delegate someDelegate)
{
... // Exactly as before
}
LogStep((Action<string, string>)DoSomething);
You do have to manually cast at the invocation, sadly, otherwise the compiler gives you an error; you can keep the same signature for the LogStep method itself, though. Alternatively, you could use a simple T4 template to create multiple overloads of the LogStep method so that you can avoid the explicit cast in your hand-written code.

Making a compiled constructor expression with just the Type of the type

I've been playing around, partially reinventing wheels so that I can understand how proper wheels spin round.
Consider this generic function for compiling and returning the default constructor of a type.
public static Func<TConcrete> Creator<TConcrete>()
{
// All checking removed for brevity
var ctor = typeof(TConcrete).GetConstructor(new Type[0]);
var lambda = Expression.Lambda<Func<TConcrete>>(Expression.New(ctor));
return lambda.Compile();
}
I believe this will return me a nice typed delegate that I can use to instantiate the passed type.
Now consider, I want a function that would do this for a set of different types, how would I go about that? I was thiking along the lines of ...
public static IEnumerable<Delegate> Creators(IEnumerable<Type> types)
{
foreach (var type in types)
{
var ctor = type.GetConstructor(new Type[0]);
var lamda = Expression.Lambda<Func<????>>(Expression.New(ctor));
yield return lambda.Compile();
}
}
As you can see from the ???? this is where I got stuck. Is there a way to do this or is my approach just flawed?
You can use a different Expression.Lambda call which takes the delegate type as a Type:
Type delegateType = typeof(Func<>).MakeGenericType(type);
var lambda = Expression.Lambda(delegateType, Expression.New(ctor));
yield return lambda.Compile();
Note that this overload of Lambda returns the non-generic LambdaExpression type rather than Expression<TDelegate> - but it still exposes a Compile method which returns Delegate, which is all you need here. Basically it's just avoiding some of the compile-time type checking you benefit from in your "known delegate type" code.
Use the non-generic overload in combination with MakeGenericType:
var lamda = Expression.Lambda<Func<????>>(Expression.New(ctor));
Should become:
var funcType = typeof(Func<>).MakeGenericType(type);
var lamda = Expression.Lambda(funcType, Expression.New(ctor));

How to make a function private to a method?

I'm working on a method that needs to repeat a small operation at different spots, but the code to be repeated should be private to the method. The obvious solution is a nested function. Whatever I try however, the C# compiler barfs at me.
Something roughly equal to this Perl snippet:
my $method = sub {
$helper_func = sub { code to encapsulate };
# more code
&$helper( called whenever needed );
# more code
}
is what I am talking about, and what I'm trying to accomplish in C#.
No other method in the class should be able to access the helper function in this context. The most logical means of writing this construct in C#, as it appears to me would be something like this:
var helper = (/* parameter names */) => { /* code to encapsulate */ };
And actually make the compiler earn its keep.
Since such an assignment is forbidden, as is the equivalent using the older delegate(){} syntax in place of the lambda, and so is declaring a delegate type within a method—what csc actually allows me to write however, is this:
private delegate /* return type */ Helper(/* parameters */);
private /* return type */ method(/* parameters */) {
Helper helper = (/* parameter names */) => {
/* code to encapsulate */
};
// more code
helper( /* called whenever needed */ );
// more code
}
Which is all fine and dandy for not copy and pasting a chunk of code around and editing the parameters by hand but it leaks a private delegate type to the rest of the class rather than keeping it private to the method. Which defeats the purpose in the first place. Using goto statements and local variables for parameters would provide better encapsulation of "helper" in this context without sacrificing code reuse. If I wanted to simulate function calls by passing parameters through registers, I think would rather use an assembler. I haven't found an acceptable way of refactoring the code to avoid the problem altogether either.
So, is it even possible to force this Common Object Oriented Language to obey?
You actually can do this in C#.
Func<T1, T2, ..., TReturn> myFunc = (a, b, ...) =>
{
//code that return type TReturn
};
If you need an anonymous method of return type void use Action instead of Func:
Action<T1, T2, ...> myAction = (a, b, ...) =>
{
//code that doesn't return anything
};
If you are in C# 3.5 or higher you can take advantage of the lambdas and convenience delegate declarations Func<> and Action<>. So for instance
void DoSomething()
{
Func<int,int> addOne = (ii) => ii +1;
var two = addOne(1);
}
The reason you can't do
var addOne = (ii) => ii +1;
is because of Homoiconicity, the lambda can be interpreted as two different constructs, a delegate and an expression tree. Thus the need to be explicit in declaration.
If you explicitly type it, it will work, i.e.
Action<paramType1, paramType2> helperAction = (/* parameter names */) => { /* code to encapsulate */ };
Func<paramType1, paramType2, returnType> helperFunction = (/* parameter names */) => { /* code to encapsulate */ };
The reason var doesn't work is that a lambda expression can evaluate to multiple types (I believe either a delegate or expression tree, but don't quote me on that) and the compiler in this situation is unable to infer which was meant.
I recommend looking at the Action<T> and Func<TResult> delegates and their overloads. You can do something like this
static void Main(string[] args)
{
SomeMethod();
}
private static void SomeMethod()
{
Action<int> action = (num) => Console.WriteLine(num);
Enumerable.Range(1,10).ToList().ForEach(action);
Console.ReadKey();
}
Here SomeMethod is private and has a local Action<int> delgate that takes an int and does something to it.
I think the issue that you came across is that you can't use implicit typing (i.e. use var) when assigning a lambda expression to a variable.
You can't use the var keyword with lambdas or delegates because they both require additional context information (delegates require a return type, and lambdas require a return type and parameter types). For instance, the (params) => { code } syntax requires to be able to infer the parameter types and return types to work: you do this by explicitly giving it a type.
The generic System.Action delegate type (returns void) could do a good job at what you're trying:
Action<ArgumentType1, ArgumentType2, ...> myDelegate = (params) => { code };
Otherwise, there's also the System.Func, which has a return type, that must be passed as the last generic argument.
It depends on what your definition of hiding is.
The func/action solution (like the one Scott suggests)
void DoSomething()
{
Func<int,int> addOne = (ii) => ii +1;
var two = addOne(1);
}
Feals like hidding the method definition when writing regular C# code BUT is when looking at the IL equivalent of
//This is pseudo code but comes close at the important parts
public class Class1
{
//The actual type is different from this
private static Func<int, int> myMethod = AnonymousFunction;
public void f()
{
myMethod(0);
}
private static int AnonymousFunction(int i)
{
return 1;
}
}
So if you really want to get to the method from outside of the one "hidding" it you can do this with reflection The actual name generated for the field storing the delegate is illegal in C# bul valid in CLR context but that's the only thing that stand in the way of using the delegate as a regular delegate stored in a field (that is if you figue out the name :) )
It's quite simple actually. As the Method seems to have another responsibility than your current Class (why else would you hide this method) move your method into it's own Class and the part you want to have private into a private method in the new class.

Get Method Name Using Lambda Expression

I'm trying to get the name of a method on a type using a lambda expression. I'm using Windows Identity Foundation and need to define access policies with the type name with namespace as a resource and the method name as the action. Here is an example.
This is the type I would be getting the type name and method name from:
namespace My.OrderEntry {
public class Order {
public void AddItem(string itemNumber, int quantity) {}
}
}
This is how I would like to define the access policy through a DSL:
ForResource<Order>().Performing(o => o.AddItem).AllowUsersHaving(new Claim());
From that statement, I would like to get "My.OrderEntry.Order" as the resource and "AddItem" as the action. Getting the type name with namespace is no problem, but I don't think I can use a lambda for a method like I'm trying to do.
public static IPermissionExp Performing<T>(
this IActionExp<T> exp,
Func<T, delegate???> action) {} //this is where I don't know what to define
Is this sort of thing even possible to do? Is there another way to do this sort of thing without using magic strings?
There are two ways to do this:
1: You could make overloads that take the various Func and Action delegates(eg Expression<Func<T, Func<TParam1,TParam2, TReturn>>. Note that your callers would need to specify the generic parameters explicitly, either in the method call or by creating the delegate. This would be used like this:
ForResource<Order>().Performing(o => new Action<string>(o.AddItem)).AllowUsersHaving(new Claim());
2: You could take an Expression<Action> that contains a method call, and parse out the MethodInfo being called from the expression tree. This would be used like this:
ForResource<Order>().Performing(o => { o.AddItem(null); }).AllowUsersHaving(new Claim());
It looks like this is what you are looking for if you want the name of the action delegate method passed in to the Performing function.
public static IPermissionExp Performing<T>(
this IActionExp<T> exp,
Expression<Action<T, string, int>> action)
{
var expression = action.Body as MethodCallExpression;
string actionMethodName = string.Empty;
if (expression != null)
{
actionMethodName = expression.Method.Name;
}
// use actionMethodName ("AddItem" in the case below) here
}
This would allow you to call the method like this...
ForResource<Order>().Performing((o, a, b) => o.AddItem(a, b)).AllowUsersHaving(new Claim());
I recently did a thing at work where you defined the a method using a lambda, which the internal object then took the name of. You could use strings as well, or pass in a MethodInfo but the first one isn't really type safe (and typos are a big risk), and the latter is not very elegant.
Basically I had a method like this (this is not the exact method, it is a bit more advanced):
public void SetRequest(Request req, Expression<Func<Service, Func<long, IEnumerable<Stuff>>> methodSelector);
The key here is the "Expression" thing, this lets you "select" a method like this:
SetRequest(req, service => service.SomeMethodTakingLongReturningStuffs);
Method selector is made into a expression tree which you can then fetch different bits of data from. I don't recall exactly what the resulting tree looks like, it also depends on how your lambdas look.
You could pass it in as a Action instead, which doesn't force any return type. It is still a little messy though, because you have to pass some arguments to the method in order for it to compile.

Categories