Build expression tree for method decoration? - c#

I’m building a class named CommandHandler that have ExecuteCommand method that have Command as input parameter.
The Idea is that ExcecuteCommand will check command name and execute proper class method by the name pattern so when command name is Test class should have corresponding TestHandler method.
On initialization I’m using reflection to find all methods and create a mapping between command name and created Func<Command, Task<object>>. For now I have achieve this by making all methods return Task<object> and use Delegate.CreateDelegate to create Func<Command, Task<object>> from reflected method but I would like to clean code and allow methods to return simple types like int or Task<custom class>.
I would like to build some simple Expression that for simple types will execute method and do Task.FromResult dynamically so class method remains clean. For Task with specific type result I would like to create expression that will result Task<object> so all could be cached as Dictionary<string, Func<Command, Task<object>>.
public class CommandHandler
{
public Dictionary<string, Func<Command, Task<object>>> methodCache = new Dictionary<string, Func<Command, Task<object>>>();
public int IntCommandHandler(Command c)
{
return 5;
}
public string StringCommandHandler(Command c)
{
return "5";
}
public Task<int> AsyncIntCommandHandler(Command c)
{
return Task.Run(() => 5);
}
public async Task<object> OldWayCommandHandler(Command c)
{
return "5";
}
private void RegisterAsyncQueryHandlers(Dictionary<string, MethodInfo> handlers)
{
var filtered = handlers.Where(h => h.Value.ReturnType == typeof(Task<object>)).ToList();
foreach (var handler in filtered)
{
methodCache.Add(handler.Key, (Func<Command, Task<object>>)Delegate.CreateDelegate(typeof(Func<Command, Task<object>>), this, handler.Value, false));
}
}
public void FillCache()
{
// Get all methods with proper pattern and pass it to RegisterAsyncQueryHandlers in dictionary of command name and MethodInfo
//RegisterAsyncQueryHandlers
}
public Task<object> ExecuteCommand(Command c)
{
return methodCache[c.Name].Invoke(c);
}
}
public class Command
{
public string Name { get; set; }
}
I have no experience with using Expressions and most of the samples I found are using basic operators and static methods. Maybe someone can help me ho w to build such expression?

If I understand correctly, the question is how to convert Task<TResult> to Task<object>.
It can be done for instance using the Task<TResult>.ContinueWith method as follows:
static Task<object> Convert<TResult>(Task<TResult> source)
{
return source.ContinueWith(t => (object)t.Result);
}
It's possible to dynamically build such expression, but the easier would be to put the above method in your class and "call" it via the following Expression.Call overload.
The method that builds expression and compiles a delegate from it could be like this:
Func<Command, Task<object>> MakeFunc(MethodInfo handler)
{
var c = Expression.Parameter(typeof(Command), "c");
var task = Expression.Call(Expression.Constant(this), handler, c);
if (task.Type != typeof(Task<object>))
task = Expression.Call(GetType(), "Convert", new[] { task.Type.GetGenericArguments().Single() }, task);
var expr = Expression.Lambda<Func<Command, Task<object>>>(task, c);
return expr.Compile();
}

Related

Type.GetMethod() for polymorphic method (both generic and non-generic)

I am currently creating a custom way of deep-copying my objects. I use a static class for this functionality.
public static class CopyServer
{
public static int CopyDeep(int original)
{
return original;
}
//not shown: same for all other value types I use (long, float,...)
public static T CopyDeep<T>(T original) where T: ICopyAble
{
if (original == null)
return default;
if (original is ICopyAutofields)
return CopyAutofields(original);
return (T)original.CopyDeep();
}
private static T CopyAutofields<T>(T original)
{
Delegate del;
if (!_copyFunctions.TryGetValue(typeof(T), out del))
{
//not shown: Building expression for parameter etc.
foreach (var fieldInfo in typeof(T).GetFields())
{
//not shown: checking options set by custom attributes
MethodInfo methodInfo = typeof(CopyServer).GetMethod("CopyDeep", new[] { fieldInfo.FieldType });
//I can't remove the second param without getting an AmbiguousMatchException
if (methodInfo == null)
{
throw new Exception($"CopyDeep not defined for type {fieldInfo.FieldType}");
}
if (methodInfo.IsGenericMethod)
methodInfo = methodInfo.MakeGenericMethod(fieldInfo.FieldType);
Expression call = Expression.Call(methodInfo, readValue);
//not shown: Assign Expression
}
//not shown: return Expression and compiling
}
return ((Func<T, T>)del)(original);
}
}
I use T CopyAutofields<T> to build functions (by building and compiling Expression Trees) so I don't have to create copy-functions for each and every class I want to copy by hand. I control the copy-behaviour with Custom Attributes (I left this part in the code above since it is not relevant for my problem).
The code works fine as long as long as only fields with types for which a non-generic function exists are used. But it is not able to retrieve my generic function T CopyDeep<T>.
Example:
//This works:
public class Manager : ICopyAble,ICopyAutofields
{
public string FirstName;
public string LastName;
}
//This doesn't
//Meaning: typeof(CopyServer).GetMethod("copyDeep", new[] { fieldInfo.FieldType });
//in T copyAutofields<T> returns null for the Manager-field and my exception gets thrown
public class Employee : ICopyAble,ICopyAutofields
{
public string FirstName;
public string LastName;
public Manager Manager;
}
//This is what I was using before I started using the ICopyAutofields.
//This approach works, but its' too much too write since my classes usually
//have way more than three fields and I occasionally forget to update
//copyDeep()-function if I add new ones.
public class Employee : ICopyAble,ICopyAutofields
{
public string FirstName;
public string LastName;
public Manager Manager;
public IModable CopyDeep()
{
var result = new Employee();
result.FirstName = CopyServer.copyDeep(FirstName);
result.LastName= CopyServer.copyDeep(LastName);
result.Manager= CopyServer.copyDeep(Manager);
return result;
}
}
Long story short: I need a way of getting a matching function for a type T if both generic and non-generic functions with the right name exist.
In .NET 4.7.1 you need to use method GetMethods and filter the results:
class MyClass
{
public T M<T>(T t) { return default(T); }
public int M(int t) { return 0; }
}
var m = typeof(MyClass).GetMethod("M", new[] { typeof(string) }); // null
var m1 = typeof(MyClass).GetMethods()
.Where(mi => mi.Name == "M" && mi.GetGenericArguments().Any())
.First(); // returns generic method
In .NET Standard 2.1 (and .NET Core since 2.1) there is another way to resolve generic type arguments - Type.MakeGenericMethodParameter, like you can see it in this answer.
Also as workaround you can move your copyAutofields<T> method to generic class like CopyAutoFieldServer<T>:
public static class CopyAutoFieldServer<T>
{
public static T copyAutofields(T original) { ... }
}

Pass generic method omitting its parameters?

Is there a way to pass a method name in a generic manner, without passing its parameters, so it can be invoked by the method, with passed arguments?
Consider this example:
public class Client
{
public string Convert(int value)
{
return value.ToString();
}
}
public class Wrapper<TClient>
{
TClient Client;
public TResult Invoke<TArg, TResult>(Func<TClient, TArg, TResult> action, TArg arg)
{
return action(Client, arg);
}
}
I want to be able to pass to the wrapper the method of TClient I want to invoke, and pass the actual arguments along, all generically:
var wrapper = new Wrapper<Client>();
wrapper.Invoke(c => c.Convert, 5);
Is there any possible way to achieve that, without hard coding the method name, or losing its genericness (i.e. by using Delegate)?
Notes:
The Client is an external sealed class that exposes a gazillion methods each of many parameters. I want wrap its behavior and I don't mind writing all the necessary code in the wrapper, but the usage of the wrapper should be as clean as possible.
Update
I want to avoid the need to specify the parameters. The whole idea is having them inferred from the specified action.
You're very close to getting your code to run. There are two options.
First, you can try this:
public class Wrapper<TClient>
{
public TResult Invoke<TArg, TResult>(Func<TArg, TResult> action, TArg arg)
{
return action(arg);
}
}
Then call it like this:
var wrapper = new Wrapper<Client>();
wrapper.Invoke(wrapper.client.Convert, 5);
Or, alternatively, you can do this:
public class Wrapper<TClient>
{
public Wrapper(TClient client)
{
this.Client = client;
}
private TClient Client;
public TResult Invoke<TArg, TResult>(Func<TClient, TArg, TResult> action, TArg arg)
{
if (operation.Target != Client)
throw new ArgumentException(nameof(operation));
return action(this.Client, arg);
}
}
And call it like this:
var client = new Client();
var wrapper = new Wrapper<Client>(client);
wrapper.Invoke((c, a) => c.Convert(a), 5);
But, from your description of your problem, I don't see how either of these help and I don't see how to implement what you're asking. Perhaps you need to provide more detail as to what the underlying need you're trying to solve?
You want the expression being passed to Invoke to return a Func that accepts TArg. In code:
public class Wrapper<TClient>
{
TClient Client;
public TResult Invoke<TArg, TResult>(Func<TClient, Func<TArg, TResult>> action, TArg arg)
{
return action(Client)(arg);
}
}
You can then invoke it like so:
class Program
{
static void Main(string[] args)
{
var wrapper = new Wrapper<Client>();
string result = wrapper.Invoke<int, string>(c => c.Convert, 5);
}
}
Since you don't like the approach of having to explicitly specify type arguments, you can use a slightly different API (which comes with its own annoyances):
public class Wrapper<TClient>
{
TClient Client;
public void Invoke<TArg, TResult>(Func<TClient, Func<TArg, TResult>> action, TArg arg, out TResult result)
{
return action(Client)(arg);
}
}
You can call this like so, with the return type inferred from the out parameter:
class Program
{
static void Main(string[] args)
{
var wrapper = new Wrapper<Client>();
string result;
wrapper.Invoke(c => c.Convert, 5, out result);
}
}

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.

Attribute Constructor With Lambda

It is possible to do this:
public static void SomeMethod<TFunc>(Expression<TFunc> expr)
{
//LambdaExpression happily excepts any Expession<TFunc>
LambdaExpression lamb = expr;
}
and call it elsewhere passing a lambda for the parameter:
SomeMethod<Func<IQueryable<Person>,Person>>( p=>p.FirstOrDefault());
I would instead like to pass an expression as a parameter to an attribute constructor.
Is it possible to do the below?
class ExpandableQueryAttribute: Attribute {
private LambdaExpression someLambda;
//ctor
public ExpandableQueryMethodAttribute(LambdaExpression expression)
{
someLambda = expression
}
}
//usage:
static LambdaExpression exp =
(Expression<Func<IQueryable<Person>, Person>>)
(p => p.FirstOrDefault());
[ExpandableQueryAttribute(exp)] //error here
// "An attribute argument must be a constant expression, typeof expression
// or array creation expression of an attribute parameter type"
My goal is to specify a method or lambda in the constructor of the attribute(even if I have to declare a full named method and pass the name of the method somehow, that'd be fine to).
Parameter types can change, but it is important that the attribute constructor can take that parameter and in some way be able to assign it to a field of type LambdaExpression
I want the declaration of the lambda/method to be just above the call to the attribute constructor, or inline, so that you don't have to go far to see what is being passed.
So these alternatives would be fine, but no luck getting them to work:
public static ... FuncName(...){...}
[ExpandableQueryAttribute(FuncName)]
// ...
or
//lambdas aren't allowed inline for an attribute, as far as I know
[ExpandableQueryAttribute(q => q.FirstOrDefault())]
// ...
The existing work around is to pass a number ID to the constructor(satisfying the "argument must be a constant" requirement), which is used by the constructor to do a lookup in a dictionary where expressions have been added previously. Was hoping to improve/simplify this, but I have a feeling it doesn't get any better due to limitations on attribute constructors.
how about this:
class ExpandableQueryAttribute : Attribute
{
private LambdaExpression someLambda;
//ctor
public ExpandableQueryAttribute(Type hostingType, string filterMethod)
{
someLambda = (LambdaExpression)hostingType.GetField(filterMethod).GetValue(null);
// could also use a static method
}
}
this should let you assign your lambda to a field and then suck it in at runtime, although in general I would prefer to use something like PostSharp to do this at compile time.
simple usage example
public class LambdaExpressionAttribute : Attribute
{
public LambdaExpression MyLambda { get; private set; }
//ctor
public LambdaExpressionAttribute(Type hostingType, string filterMethod)
{
MyLambda = (LambdaExpression)hostingType.GetField(filterMethod).GetValue(null);
}
}
public class User
{
public bool IsAdministrator { get; set; }
}
public static class securityExpresions
{
public static readonly LambdaExpression IsAdministrator = (Expression<Predicate<User>>)(x => x.IsAdministrator);
public static readonly LambdaExpression IsValid = (Expression<Predicate<User>>)(x => x != null);
public static void CheckAccess(User user)
{
// only for this POC... never do this in shipping code
System.Diagnostics.StackTrace stackTrace = new System.Diagnostics.StackTrace();
var method = stackTrace.GetFrame(1).GetMethod();
var filters = method.GetCustomAttributes(typeof(LambdaExpressionAttribute), true).OfType<LambdaExpressionAttribute>();
foreach (var filter in filters)
{
if ((bool)filter.MyLambda.Compile().DynamicInvoke(user) == false)
{
throw new UnauthorizedAccessException("user does not have access to: " + method.Name);
}
}
}
}
public static class TheClass
{
[LambdaExpression(typeof(securityExpresions), "IsValid")]
public static void ReadSomething(User user, object theThing)
{
securityExpresions.CheckAccess(user);
Console.WriteLine("read something");
}
[LambdaExpression(typeof(securityExpresions), "IsAdministrator")]
public static void WriteSomething(User user, object theThing)
{
securityExpresions.CheckAccess(user);
Console.WriteLine("wrote something");
}
}
static void Main(string[] args)
{
User u = new User();
try
{
TheClass.ReadSomething(u, new object());
TheClass.WriteSomething(u, new object());
}
catch(Exception e)
{
Console.WriteLine(e);
}
}
This is not possible because what you can pass into an attribute needs to fit into the CLR's binary DLL format and there is no way to encode arbitrary object initialization. For the same you you cannot pass a nullable value for example. The restrictions are very strict.
Although you cannot have complex constructor for attributes, in some situation a work-aound is to have a public property for that attribute and update it at run-time.
self point to an object of the class that contains some attributes on its properties. LocalDisplayNameAttribute is a custom attribute.
The following code will set ResourceKey property of my custom attribute class at run-time. Then at that point you can override DisplayName to outpiut whatever text you want.
static public void UpdateAttributes(object self)
{
foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(self))
{
LocalDisplayNameAttribute attr =
prop.Attributes[typeof(LocalDisplayNameAttribute)]
as LocalDisplayNameAttribute;
if (attr == null)
{
continue;
}
attr.ResourceKey = prop.Name;
}
}
Use dymanic linq: http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
You can make the attribute's constructor take a string which evaluates to an expression.

How do I take a lambda expression as a parameter that returns a method?

I want to be able to do this:
var test = SomeMethod(s => s.SomeMethod);
I can make it work with properties by making the method signature look like this:
SomeMethod<TProperty>(Expression<Func<T, TProperty>> expression)
How can I make it work with methods? I know this is simple, I'm just missing something small.
Moq approaches this by requiring the method parameters to be stubbed out with special 'marker' objects like:
test.Setup(m => m.SomeMethod(It.IsAny<int>()));
Incidentally, this allows Moq to resolve method overloads (a single method name is ambiguous if you don't have any notion of the required parameters.) They are going a bit further and using it to actually match parameters based on criteria, for the purpose of mocking objects for unit testing. The source code is available and might give you some ideas. They do all sorts of fun trickery with expression trees.
Here is an example based on the Moq source (hacked out a bit, but shows how the method can be extracted from the expression):
internal static void ExtractMethod<T>(Expression<Action<T>> expression)
where T : class
{
var methodCall = expression.ToMethodCall();
var method = methodCall.Method;
var args = methodCall.Arguments.ToArray();
}
Straight from Moq source:
/// <summary>
/// Casts the body of the lambda expression to a <see cref="MethodCallExpression"/>.
/// </summary>
/// <exception cref="ArgumentException">If the body is not a method call.</exception>
public static MethodCallExpression ToMethodCall(this LambdaExpression expression)
{
Guard.NotNull(() => expression, expression);
var methodCall = expression.Body as MethodCallExpression;
if (methodCall == null)
{
throw new ArgumentException(string.Format(
CultureInfo.CurrentCulture,
Resources.SetupNotMethod,
expression.ToStringFixed()));
}
return methodCall;
}
This will work with your code, but you'd have to pass 'dummy' parameters to allow the compiler to create the expression. So if you had:
public void SomeMethod(int value, string text) {}
Then you'd pass it as:
ExtractMethod(s => s.SomeMethod(0, null));
Is something like this what you're looking for?
DoSomethingWithAction<T>(Func<T, Action> actionRetriever) { }
DoSomethingWithFunction<T, TResult>(Func<T, Func<TResult>> functionRetriever) { }
You would call these like:
DoSomethingWithAction<ObjectWithMethod>(obj => obj.Method);
DoSomethingWithFunction<ObjectWithProperty>(obj => obj.Property);
Something like this?
public SimpleCommand( Predicate<object> canExecuteDelegate, Action<object> executeDelegate )
{
CanExecuteDelegate = canExecuteDelegate;
ExecuteDelegate = executeDelegate;
}
You will need to specify the function signature using Predicate or Action.
class Program
{
public class Test
{
public bool SomeMethod(string test)
{
return true;
}
}
static void Main(string[] args)
{
Test testObj = new Test();
Func<string, bool> rule1 = AddRule(testObj, x => x.SomeMethod);
bool rsult = rule1("ttt");
}
static Func<string, bool> AddRule<T>( T obj, Func<T,Func<string, bool>> func)
{
return func(obj);
}
}
I think, there's no way of doing this without specifying the method signature: Just think of overloaded methods:
void SomeMethod() { }
int SomeMethod(int a, int b) { return 0; }
// ...
var test = TestMethod(s => s.SomeMethod);
How would the compiler possibly know, which of the methods you want to test?

Categories