Get the name of a method using an expression - c#

I know there are a few answers on the site on this and i apologize if this is in any way duplicate, but all of the ones I found does not do what I am trying to do.
I am trying to specify method info so I can get the name in a type safe way by not using strings.
So I am trying to extract it with an expression.
Say I want to get the name of a method in this interface:
public interface IMyInteface
{
void DoSomething(string param1, string param2);
}
Currently I can get the name using THIS method:
MemberInfo GetMethodInfo<T>(Expression<Action<T>> expression)
{
return ((MethodCallExpression)expression.Body).Method;
}
I can call the helper method as follows:
var methodInfo = GetMethodInfo<IMyInteface>(x => x.DoSomething(null, null));
Console.WriteLine(methodInfo.Name);
But I am looking for the version that I can get the method name without specifying the parameters (null, null)
like this:
var methodInfo = GetMethodInfo<IMyInteface>(x => x.DoSomething);
But all attempts fail to compile
Is there a way to do this?

x => x.DoSomething
In order to make this compilable I see only two ways:
Go non-generic way and specify it's parameter as Action<string, string>
Specify Action<string, string> as your target delegate type by yourself: GetMethodInfo<IMyInteface>(x => new Action<string,string>(x.DoSomething))
if you are ok to go with second one, which allows you to omit arguments then you can write your GetMethodInfo method as follows:
MemberInfo GetMethodInfo<T>(Expression<Func<T, Delegate>> expression)
{
var unaryExpression = (UnaryExpression) expression.Body;
var methodCallExpression = (MethodCallExpression) unaryExpression.Operand;
var methodInfoExpression = (ConstantExpression) methodCallExpression.Arguments.Last();
var methodInfo = (MemberInfo) methodInfoExpression.Value;
return methodInfo;
}
It works for your interface, but probably some generalization will be required to make this working with any method, that's up to you.

The following is compatible with .NET 4.5:
public static string MethodName(LambdaExpression expression)
{
var unaryExpression = (UnaryExpression)expression.Body;
var methodCallExpression = (MethodCallExpression)unaryExpression.Operand;
var methodCallObject = (ConstantExpression)methodCallExpression.Object;
var methodInfo = (MethodInfo)methodCallObject.Value;
return methodInfo.Name;
}
You can use it with expressions like x => x.DoSomething, however it would require some wrapping into generic methods for different types of methods.
Here is a backwards-compatible version:
private static bool IsNET45 = Type.GetType("System.Reflection.ReflectionContext", false) != null;
public static string MethodName(LambdaExpression expression)
{
var unaryExpression = (UnaryExpression)expression.Body;
var methodCallExpression = (MethodCallExpression)unaryExpression.Operand;
if (IsNET45)
{
var methodCallObject = (ConstantExpression)methodCallExpression.Object;
var methodInfo = (MethodInfo)methodCallObject.Value;
return methodInfo.Name;
}
else
{
var methodInfoExpression = (ConstantExpression)methodCallExpression.Arguments.Last();
var methodInfo = (MemberInfo)methodInfoExpression.Value;
return methodInfo.Name;
}
}
Check this sample code on Ideone.
Note, that Ideone does not have .NET 4.5.

The problem with this is that x.DoSomething represents a method group. And you have to somehow explicitly specify what delegate type do you want to convert that method group into, so that the correct member of the group can be selected. And it doesn't matter if that group contains only one member.
The compiler could infer that you mean that one, but it doesn't do that. (I think it's this way so that your code won't break if you add another overload of that method.)
Snowbear's answer contains good advice on possible solutions.

This is a new answer to an old question, but responds to the "verbose" complaint of the accepted answer. It requires more code, but the result is a syntax like:
MemberInfo info = GetActionInfo<IMyInterface, string, string>(x => x.DoSomething);
or, for methods with a return value
MemberInfo info = GetFuncInfo<IMyInterface, object, string, string>(x => x.DoSomethingWithReturn);
where
object DoSomethingWithReturn(string param1, string param2);
Just like the framework provides Action<> and Func<> delegates up to 16 parameters, you have to have GetActionInfo and GetFuncInfo methods that accept up to 16 parameters (or more, although I'd think refactoring is wise if you have methods with 16 parameters). A lot more code, but an improvement in the syntax.

If you are ok with using the nameof() operator you can use the following approach.
One of the benefits is not having to unwrap an expression tree or supply default values or worry about having a non-null instance of the type with the method.
// As extension method
public static string GetMethodName<T>(this T instance, Func<T, string> nameofMethod) where T : class
{
return nameofMethod(instance);
}
// As static method
public static string GetMethodName<T>(Func<T, string> nameofMethod) where T : class
{
return nameofMethod(default);
}
Usage:
public class Car
{
public void Drive() { }
}
var car = new Car();
string methodName1 = car.GetMethodName(c => nameof(c.Drive));
var nullCar = new Car();
string methodName2 = nullCar.GetMethodName(c => nameof(c.Drive));
string methodName3 = GetMethodName<Car>(c => nameof(c.Drive));

If your application would allow a dependency on Moq (or a similar library), you could do something like this:
class Program
{
static void Main(string[] args)
{
var methodName = GetMethodName<IMyInteface>(x => new Action<string,string>(x.DoSomething));
Console.WriteLine(methodName);
}
static string GetMethodName<T>(Func<T, Delegate> func) where T : class
{
// http://code.google.com/p/moq/
var moq = new Mock<T>();
var del = func.Invoke(moq.Object);
return del.Method.Name;
}
}
public interface IMyInteface
{
void DoSomething(string param1, string param2);
}

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

Dynamically creating an expression which selects an objects property

I want to be able to build up an expression dynamically, which is essentially a property selector.
I am trying to use this so I can provide a flexible search UI and then translate the selected search parameters to an Entity Framework query.
I have most of what I need thanks to another library I am using, but am missing the final part which translates my query string parameters to the appropriate expression selector the other library requires.
The library takes an argument of :
Expression<Func<TObject, TPropertyType>>
An example of how this would be coded if baked into an application would be :
Expression<Func<MyObject, int>> expression = x=> x.IntegerProperty;
However, I need to be able to generate this expression dynamically, as the important point is that all I will know is the type of object (MyObject) and the property name as a string value ("IntegerProperty"). The property value will obviously map to an property on the object which could be of any non complex type.
So essentially I think I am wanting to find a way to build up the expression dynamically which specifies the correct object property to return and where the return value is determined by that property type.
psuedo code :
string ObjectPropertyName
Type ObjectType
Type ObjectPropertyType = typeof(ObjectType).GetProperty(ObjectPropertyName).Property
Expression<Func<[ObjectType], [ObjectPropertyType]>> expression = x=> x.[ObjectPropertyName];
Update :
I have got as far as this
ParameterExpression objectParameter = Expression.Parameter(type, "x");
MemberExpression objectProperty = Expression.Property(objectParameter, "PropertyNameString");
Expression<Func<ObjectType, int>> expression = Expression.Lambda<Func<ObjectType, int>>(objectProperty, objectParameter);
But the problem I have with this is that the return type is not always an int but may be some other type.
Doing what you asked is bit tricky but not impossible. Since the property type is not known until run time so you can not declare the Expression<Func<,>> so it would be done by reflection.
public static class QueryableExtension
{
public static object Build<Tobject>(this Tobject source, string propertyName)
{
var propInfo = typeof(Tobject).GetProperty(propertyName);
var parameter = Expression.Parameter(typeof(Tobject), "x");
var property = Expression.Property(parameter, propInfo);
var delegateType = typeof(Func<,>)
.MakeGenericType(typeof(Tobject), propInfo.PropertyType);
var lambda = GetExpressionLambdaMethod()
.MakeGenericMethod(delegateType)
.Invoke(null, new object[] { property, new[] { parameter } });
return lambda;
}
public static MethodInfo GetExpressionLambdaMethod()
{
return typeof(Expression)
.GetMethods()
.Where(m => m.Name == "Lambda")
.Select(m => new
{
Method = m,
Params = m.GetParameters(),
Args = m.GetGenericArguments()
})
.Where(x => x.Params.Length == 2
&& x.Args.Length == 1
)
.Select(x => x.Method)
.First();
}
}
Usage -
var expression = testObject.Build("YourPropertyName");
Now this will build the Expression you desired with return type of property. But since we don't know about your library but I suggest you to call your library method via reflection and pass the expression wrapped under object.
As I mentioned in the comments, building expression without knowing the property type is easy (even with nested property support):
static LambdaExpression MakeSelector(Type objectType, string path)
{
var item = Expression.Parameter(objectType, "item");
var body = path.Split('.').Aggregate((Expression)item, Expression.PropertyOrField);
return Expression.Lambda(body, item);
}
But then you'll need to find a way to call your generic library method - using reflection or dynamic call.
If you have both ObjectType and ObjectPropertyType as generic type parameters, you can use the Expression class to do something like this:
public static Expression<Func<TObject, TPropertyType>> Generate<TObject, TPropertyType>(
string property_name)
{
var parameter = Expression.Parameter(typeof (TObject));
return Expression.Lambda<Func<TObject, TPropertyType>>(
Expression.Property(parameter, property_name), parameter);
}
There is old intresting library DynamicLinq. May be it will be useful for you. It extends System.Linq.Dynamic to support execution of Lambda expressions defined in a string. With use of DynamicLinq you can do somethink like:
public class IndexViewModel
{
public bool HasPassword { get; set; }
public string PhoneNumber { get; set; }
public bool TwoFactor { get; set; }
public bool BrowserRemembered { get; set; }
}
//...........
Expression<Func<IndexViewModel, bool>> ex =
System.Linq.Dynamic.DynamicExpression.ParseLambda<IndexViewModel, bool>("TwoFactor");
var model = new ReactJs.NET.Models.IndexViewModel() { TwoFactor = true };
var res = ex.Compile()(model);
// res == true
System.Diagnostics.Debug.Assert(res);

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.

How to refer to a method?

I'm trying to create a router for a web application (yes, I know solutions already exist).
Thus far I've got this:
class Route
{
public static RegexOptions DefaultOptions = RegexOptions.IgnoreCase;
Regex regex;
Type controller;
MethodInfo action;
public Route(string pattern, Type controller)
{
this.regex = new Regex(string.Format("^(?:{0})$", pattern), DefaultOptions);
this.controller = controller;
}
}
And this:
Route[] routes = {
new Route(#"/user:(?<id>\d+)", typeof(UserController))
};
When the URL matches that regex, it should call the method action in class controller. I'm thinking typeof() is the only way I can pass the class around, but how about the method?
I think MethodInfo is the object I want, because with that I should be able to invoke it, but from an API perspective, what should the 3rd argument to Route constructor be, and how should we call it?
I prefer a strongly-typed solution rather than some string shenanigans.
I don't think there is a way to refer to a instance method in c sharp without an instance. Unless you want the user of the API to define a MethodInfo object to pass in, string name may be the best way.
static class Program
{
static void Main()
{
Route r = new Route("pattern", typeof(UserController), "Action");
}
}
public class Route
{
public Route(string pattern, Type type, string methodName)
{
object objectToUse = Activator.CreateInstance(type, null);
MethodInfo method = type.GetMethod(methodName);
string[] args = new string[1];
args[0] = "hello world";
method.Invoke(objectToUse, args);
}
}
public class UserController
{
public void Action(string message)
{
MessageBox.Show(message);
}
}
You're looking for the non-existent infoof operator.
Unfortunately, it doesn't exist.
The simplest answer is to take a string.
Alternatively, you can take an expression tree.
The disadvantage to taking an expression tree is that your caller must pass all parameters.
You could work that into your framework (by taking an Expression<Func<parameters, ResultType>>), and perhaps even compile the expression tree to call the actions. (which will result in much faster calls than reflection)
You can create something like this:
MethodInfo GetMethodInfo(LambdaExpression expression)
{
var call = expression.Body as MethodCallExpression;
if(call == null) throw new ArgumentException("Must be a method call","expression");
return call.Method;
}
MethodInfo GetMethodInfo<T>(Expression<Action<T>> expression)
{
return GetMethodInfo(expression);
}
MethodInfo GetMethodInfo<T, TResult>(Expression<Func<T, TResult>> expression)
{
return GetMethodInfo(expression);
}
And use it like this:
MethodInfo action = GetMethodInfo((UserController c) => c.ActionMethod());
// or
MethodInfo action = GetMethodInfo((UserController c) =>
c.ActionMethodWithParams(default(int)));
This won't call the method immediately because it is an expression tree, i.e., a syntactic tree representing the method call.

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