Body from Func<T> - c#

how can I get a body from function
Func<bool> methodCall = () => output.SendToFile();
if (methodCall())
Console.WriteLine("Success!");
I need to get this output.SendToFile() as a string
Another example:
string log = "";
public void Foo<T>(Func<T> func)
{
try
{
var t = func();
}
catch (Exception)
{
//here I need to add the body of the lambda
// log += func.body;
}
}
public void Test()
{
var a = 5;
var b = 6;
Foo(() => a > b);
}
Edit:
For more information on this topic see: Expression Trees

You can't. A Func<T> is nothing you can easily analyze. If you want to analyze a lambda, you need to create a Expression<Func<bool>> and analyze it.
Getting the body of an expression is simple:
Expression<Func<bool>> methodCall = () => output.SendToFile();
var body = methodCall.Body;
body would be a MethodCallExpression you could further analyze or just output via ToString. Using ToString won't result exactly in what you would like to have, but it contains that information, too.
For example, executing ToString() on body in LINQPad results in something like this:
value(UserQuery+<>c__DisplayClass0).output.SendToFile()
As you can see, "output.SendToFile()" is there.
To actually execute the code defined by an expression, you first need to compile it:
var func = methodCall.Compile();
func();
Which can be shortened to this:
methodCall.Compile()(); // looks strange but is valid.

Related

C# Expression API - Capture outer variable

I am currently testing Expression API and I am strugling to create an expression (using Expression API) similar to the following:
Expression<Func<string>> SomeFunction(string a)
{
return () => a;
}
My ideia is this function, instead of a "hardcoded" expression, would be using the Expression API. So far I got this working:
Expression<Func<string>> cache = null;
Expression<Func<string>> SomeFunction2(string a)
{
if(cache != null)
return cache;
var aVariable = Expression.Constant(a, typeof(string));
cache = Expression.Lambda<Func<string>>(aVariable);
return cache;
}
The problem with the above example is, since I captuire the variable as a constant, the second time I call this method, it will not work as expected. How can I create an expression using the scope variable? Is this kind of thing even possible?
In addition to my comment. If I udnerstood your problem correctly - try something like this:
ConcurrentDictionary<string, Expression<Func<string>>> cache = new(); // using concurrent one JIC, dependent on your usecase can be an overkill
public Expression<Func<string>> SomeFunction2(string a)
{
if(cache.TryGetValue(a, out var value))
return value;
var aVariable = Expression.Constant(a, typeof(string));
var res = Expression.Lambda<Func<string>>(aVariable);
cache.TryAdd(a, res);
return res;
}

Linq.Expression TryCatch - Pass exception to Catch Block?

So I've been tinkering with Linq.Expressions (and if anyone can suggest a more proper or more elegant way to do what I'm doing please feel free to chime in) and have hit a wall in trying to do something.
Let's imagine we have a simple math class:
public class SimpleMath {
public int AddNumbers(int number1, int number2) {
return number1 + number2;
}
}
I decide I want to convert our AddNumbers method to a simple Func<object, object, object> delegate.
To do this I do the following:
// Two collections, one for Type Object paramaters and one for converting to Type int.
List<ParameterExpression> parameters = new List<ParameterExpression>();
List<Expression> convertedParameters = new List<Expression>();
// Populate collections with Parameter and conversion
ParameterExpression parameter1 = Expression.Parameter(typeof(object));
parameters.Add(parameter1);
convertedParameters.Add(Expression.Convert(parameter1, typeof(int)));
ParameterExpression parameter2 = Expression.Parameter(typeof(object));
parameters.Add(parameter2);
convertedParameters.Add(Expression.Convert(parameter2, typeof(int)));
// Create instance of SimpleMath
SimpleMath simpleMath = new SimpleMath();
// Get the MethodInfo for the AddNumbers method
MethodInfo addNumebrsMethodInfo = simpleMath.GetType().GetMethods().Where(x => x.Name == "AddNumbers").ToArray()[0];
// Create MethodCallExpression using the SimpleMath object, the MethodInfo of the method we want and the converted parameters
MethodCallExpression returnMethodWithParameters = Expression.Call(Expression.Constant(simpleMath), addNumebrsMethodInfo, convertedParameters);
// Convert the MethodCallExpression to return an Object rather than int
UnaryExpression returnMethodWithParametersAsObject = Expression.Convert(returnMethodWithParameters, typeof(object));
// Create the Func<object, object, object> with our converted Expression and Parameters of Type Object
Func<object, object, object> func = Expression.Lambda<Func<object, object, object>>(returnMethodWithParametersAsObject, parameters).Compile();
object result = func(20, 40); // result = 60
So if you run that code func should return simple calculations. However, it accepts parameters of Type Object, which obviously leaves it open to problems at runtime, for example:
object result1 = func(20, "f"); // Throws InvalidCastException
So I want to wrap the method in a Try...Catch (obviously this exact problem would be picked up at compile time if we were dealing with a straight call to AddNumbers and passing a string as a parameter).
So to catch this exception I can do the following:
TryExpression tryCatchMethod = TryExpression.TryCatch(returnMethodWithParametersAsObject, Expression.Catch(typeof(InvalidCastException), Expression.Constant(55, typeof(object))));
Func<object, object, object> func = Expression.Lambda<Func<object, object, object>>(tryCatchMethod, parameters).Compile();
object result = func(20, "f"); // result = 55
The TryExpression.TryCatch takes an Expression body and then a collection of CatchBlock handlers. returnMethodWithParametersAsObject is the expression we wish to wrap, Expression.Catch defines that the Exception we want to catch is of Type InvalidCastException and its Expression body is a constant, 55.
So the exception is handled, but it's not much use unless I want to always return a static value when the exception is thrown. So returning to the SimpleMath class I add a new method HandleException:
public class SimpleMath {
public int AddNumbers(int number1, int number2) {
return number1 + number2;
}
public int HandleException() {
return 100;
}
}
And following the same process above I convert the new method to an Expression:
MethodInfo handleExceptionMethodInfo = simpleMath.GetType().GetMethods().Where(x => x.Name == "HandleException").ToArray()[0];
MethodCallExpression returnMethodWithParameters2 = Expression.Call(Expression.Constant(simpleMath), handleExceptionMethodInfo);
UnaryExpression returnMethodWithParametersAsObject2 = Expression.Convert(returnMethodWithParameters2, typeof(object));
Then using it when creating the TryCatch block:
TryExpression tryCatchMethod2 = TryExpression.TryCatch(returnMethodWithParametersAsObject, Expression.Catch(typeof(InvalidCastException), returnMethodWithParametersAsObject2));
Func<object, object, object> func = Expression.Lambda<Func<object, object, object>>(tryCatchMethod2, parameters).Compile();
object result = func(20, "f"); // result = 100
So this time when the InvalidCastException is thrown the SimpleMath.HandleException method will be executed. So far so good, I can now execute some code when there is an exception.
My problem now is, in a normal inline Try...Catch block you actually have the exception object at your disposal. E.g.
try {
// Do stuff that causes an exception
} catch (InvalidCastException ex) {
// Do stuff with InvalidCastException ex
}
I can execute code when an exception is thrown but I can't seem to figure out how to actually get my hands on the exception object like you would in a normal Try...Catch block.
Any help would be appreciated!
p.s. I know that you wouldn't actually organise anything in the way I've done above but I thought it was necessary for example purposes to show the mechanics of what I want to do.
You need to pass your catched exception to CatchBlock expression as parameter.
For this you should do:
Change signature of HandleException. It will takes a exception as argument:
public int HandleException(InvalidCastException exp)
{
// Put here some real logic. I tested it using line below
Console.WriteLine(exp.Message);
return 100;
}
Use CatchBlock.Variable to pass your handled exception into catch block. You can set it use constructor. Read comment in the code below:
// Create parameter that will be passed to catch block
var excepParam = Expression.Parameter(typeof(InvalidCastException));
MethodInfo handleExceptionMethodInfo = simpleMath.GetType().GetMethods().Where(x => x.Name == "HandleException").ToArray()[0];
MethodCallExpression returnMethodWithParameters2 = Expression.Call(Expression.Constant(simpleMath), handleExceptionMethodInfo, excepParam);
UnaryExpression returnMethodWithParametersAsObject2 = Expression.Convert(returnMethodWithParameters2, typeof(object));
// Put created parameter before to CatchBlock.Variable using Expression.Catch
// that takes the first argument as ParameterExpression
TryExpression tryCatchMethod2 = TryExpression.TryCatch(returnMethodWithParametersAsObject, Expression.Catch(excepParam, returnMethodWithParametersAsObject2));
var exppp = Expression.Lambda<Func<object, object, object>>(tryCatchMethod2, parameters);
Func<object, object, object> func2 = Expression.Lambda<Func<object, object, object>>(tryCatchMethod2, parameters).Compile();
object result2 = func2(20, "f"); // result = 100
#GeorgeAlexandria's answer is fully correct. But I found it very hard work to decode it all when I came to do the same thing.
Perhaps the following code (written as 2 helper methods), will help the next person who needs to do something like this ...
private Expression WrapActionExpressionIn_Try_Catch_ThrowNewMessage(Expression coreExpression, string newMessage)
{
return
Expression.TryCatch(
coreExpression,
Expression.Catch(typeof(Exception),
Expression.Throw(
Expression.Constant(new Exception(newMessage))
)
));
}
private Expression WrapActionExpressionIn_Try_Catch_RethrowWithAdditionalMessage(Expression coreExpression, string additionalMessage)
{
var caughtExceptionParameter = Expression.Parameter(typeof(Exception));
//We want to call `new Exception(additionalMessage, caughtException)`
var ctorForExceptionWithMessageAndInnerException = typeof(Exception).GetConstructor(new[] {typeof(string), typeof(Exception)});
var replacementExceptionExpresion = Expression.New(ctorForExceptionWithMessageAndInnerException, Expression.Constant(additionalMessage), caughtExceptionParameter);
return
Expression.TryCatch(
coreExpression,
Expression.Catch(caughtExceptionParameter,
Expression.Throw( replacementExceptionExpresion )
));
}
These two methods both start from a premise of "we already have an Expression representing an Action<TInstance> that we are about to invoke. And now we want to add a try-catch around that Action."
Without the Try-Catch, we would have done:
Action finalLamda = Expression.Lambda<Action<TInstance>>(actionExpression, instanceExpression).Compile();
now we do:
var actionWithTryCatchExpression = WrapActionExpressionIn_Try_Catch_RethrowWithAdditionalMessage(actionExpression);
Action finalLamda = Expression.Lambda<Action<TInstance>>(actionWithTryCatchExpression, instanceExpression).Compile();
Respectively the two helpers represent:
try
{
action();
}
catch(Exception)
{
throw new Exception(newMessage);
}
\\and
try
{
action();
}
catch(Exception e)
{
throw new Exception(additionalMessage, e);
}

Convert C# function call to a string

I would like to create a function that converts a "C# function call" to a string.
For example:
In my C# Project there is a public function, that can be called like this:
myTestClass.myTestFunction();
It's a function without arguments and returnvalue.
Now I would like to implement another function that accepts a C#
"Expression" as argument and converts the "Expression" to a string:
Expression<Func<???>> expr = () => myTestClass.myTestFunction();
string myString="";
myString=convertExpressionToString(expr);
myString should contain now "myTestClass.myTestFunction();"
It is important that the complete function call including the class
name is inside the string.
Any ideas how to solve this?
For this case you can simply write
private static string ConvertExpressionToString(LambdaExpression expr)
{
var methodCallExpr = expr.Body as MethodCallExpression;
if (methodCallExpr != null ) {
return methodCallExpr.Method.DeclaringType.Name + "." +
methodCallExpr.Method.Name + "();";
}
}
The general case is more complicated; however, this gives you an idea of where to start.
A more elaborate version prints parameters passed as constant expressions:
private static string ConvertExpressionToString(LambdaExpression expr)
{
var sb = new StringBuilder();
var methodCallExpr = expr.Body as MethodCallExpression;
sb.Append(methodCallExpr.Method.DeclaringType.Name)
.Append(".")
.Append(methodCallExpr.Method.Name)
.Append("(");
var arguments = methodCallExpr.Arguments;
for (int i = 0; i < arguments.Count; i++) {
if (i > 0) {
sb.Append(", ");
}
var constExpr = arguments[i] as ConstantExpression;
if (constExpr == null) {
sb.Append("<expr>");
} else {
sb.Append(constExpr.ToString());
}
}
sb.Append(");");
return sb.ToString();
}
It can cope with this expression:
Expression<Action> expr = () => myTestClass.myTestFunction(5, "hello");
However, since the parameters can be any valid expressions, it quickly becomes complicated to include other cases. And then there are out and ref parameters and optional parameters.
Just call ToString on the method's body.
string myString = expr.Body.ToString();
what you're trying to get is an action
Expression<Action> expr = () => myTestClass.myTestFunction();
MethodCallExpression mbr = (MethodCallExpression)expr.Body;
String methodName = mbr.Method.Name;
Assert.AreEqual(methodName, "myTestFunction");
MemberExpression me = (MemberExpression) mbr.Object;
String memberName = me.Member.Name;
Assert.AreEqual(methodName, "myTestClass");
String finalName = string.Format("{0}.{1}()", memberName, methodName);
Assert.AreEqual("myTestClass.myTestFunction()", finalName);
because you're accessing myTestClass via a closure you need to realize that you're accessing it via a Member Expression
so the body is a Method call. we get the method name from that, then we get the expression representing the object that we're calling the method on, we cast that to a member expression because that's what it is in this case and we get the name from the member on that member expression.

Does an expression tree Parameter need to reuse same instance?

I'm using a combination of reflection and expression trees, and want to pass back certain property accessors from a class to a calling method. My current code has a method traversing the class and returning a list of MemberExpressions. The caller then iterates over the member expressions and creates lambdas, which should then be called with an instance of the inspected class to return the value of the property.
Here is a sample of what it would look like without the method calls (Runnable in LINQPad):
void Main()
{
var t = new Test { Prop = "Test" };
var property = t.GetType().GetProperty("Prop");
var baseType = Expression.Parameter(typeof(Test), "baseType");
var memberAccess = Expression.MakeMemberAccess(baseType, property);
var lambda = Expression.Lambda<Func<Test, string>>(memberAccess, Expression.Parameter(typeof(Test), "baseType"));
var func = lambda.Compile();
var result = func(t);
result.Dump();
}
class Test {
public string Prop { get; set; }
}
This does not work, throwing this exception:
InvalidOperationException: variable 'baseType' of type 'UserQuery+Test' referenced from scope '', but it is not defined
However, if I change the creation of the lambda to this:
var lambda = Expression.Lambda<Func<Test, string>>(memberAccess, baseType);
That is, replace the Expression.Parameter with the variable used earlier, then it works. This is not (easily) possible in the scenario where I want to use it, since I would have to return the original parameter along with the list (I could return a tuple, of course, but I would prefer not to, if it is not necessary).
Why does it work like this? Inspecting the DebugView of the lambda, they are exactly the same no matter what approach is used:
.Lambda #Lambda1<System.Func`2[UserQuery+Test,System.String]>(UserQuery+Test $baseType)
{
$baseType.S
}
Yes, you need to refer ParameterExpression, used earlier. This won't compile too:
private String Foo(Test myParam)
{
return myAnotherParam.MyProperty;
}
With instatiating new ParameterExpression in lambda, you're doing the same thing (but note, when making lambda, you're doing it in reversed order - first, you're constructing a method body, then - a method declaration):
// return myAnotherParam.MyProperty;
var baseType = Expression.Parameter(typeof(Test), "baseType");
var memberAccess = Expression.MakeMemberAccess(baseType, property);
// private String Foo(MyClass myParam)
var lambda = Expression.Lambda<Func<Test, string>>(memberAccess, Expression.Parameter(typeof(Test), "baseType"));

Assigning property of anonymous type via anonymous method

I am new in the functional side of C#, sorry if the question is lame.
Given the following WRONG code:
var jobSummaries = from job in jobs
where ...
select new
{
ID = job.ID,
Description = job.Description,
FileName = (job) => {
// primitive logic not
// worth to become a named method
try { return job.Files[0].LocalName); }
catch { return null as string; }
}
};
This code produces the following justified compiler error:
cannot assign lambda expression to
anonymous type property
The code above would set the delegate to the FileName property. But that is not my aim. I want the code work like this but without naming the method:
var jobSummaries = from job in jobs
where ...
select new
{
ID = job.ID,
Description = job.Description,
FileName = this.ExtractFileName(job)
};
...
private string ExtractFileName(Job job)
{
try { return Path.GetFileName(job.Files[0].LocalName); }
catch { return null as string; }
}
Any suggestions?
To call an anonymous function directly, this works:
int result = new Func<int, int>( (int i) =>{ return i + 5; } ).Invoke(3);
// result = 8
But I agree, int result = (i => i + 5)(3); would be way cooler =)
As far as I know, you can't inline lambda expressions like that because a lamda expression is an instance itself (of the type Expression<Func<T>> or similar).
However, you can do this (updated with calculation of fileName, since this is now provided by the OP):
var jobSummaries = from job in jobs
where ...
let fileName = job.Files.Select(f => f.LocalName).FirstOrDefault()
select new
{
ID = job.ID,
Description = job.Description,
FileName = fileName
};
Notice the use of the let keyword, that lets you extract the filename from the job variable directly inside the LINQ expression.
The compiler is complaining because you are not calling your lambda function, you are defining it. If the compiler would let you, you'd have a FileName property that is a function rather than a value.
If you can write your "primitive logic" as an expression, you can write that directly in the assignment statement.
How about using extension for select. So you can do your little logic inside
var jobSummaries = jobs.Select(j =>
{
var someVar = j + "bla";
return new
{
somelogic = someVar
};
});

Categories