I'm trying to pass an expression that describes a method but I want the argument to be strongly typed and I don't want to have to know the method signature or pass the arguments in the expression, something like this:
GetMethod<MyClass>(c => c.DoSomething);
Where DoSomething could have a method signature like this... string DoSomething(int id, int count)
I know I can do something like this:
MemberInfo GetMethod<T>(Expression<Func<T, Delegate>> expression);
//implementation
GetMethod<MyClass>(c => new Func<int, int, string>(c.DoSomething))
But frankly, this is quite ugly.
Is this possible?
Just have an overload for each possible Action/Func. It won't cover all possibilities (have an extra overload that you've shown there to cover all edge cases) but it'll handle most of them.
The body of each of the action/func overloads can just call the overload that you've shown above for the actual implementation.
public MemberInfo GetMethod<T1, T2>(Expression<Func<T1, Func<T2>>> expression)
{
return GetMethodImpl(expression);
}
public MemberInfo GetMethod<T1, T2, T3>(Expression<Func<T1, Func<T2, T3>>> expression)
{
return GetMethodImpl(expression);
}
public MemberInfo GetMethod<T1, T2>(Expression<Func<T1, Action<T2>>> expression)
{
return GetMethodImpl(expression);
}
//...
GetMethodImpl can then be implemented like so:
private MemberInfo GetMethodImpl<T1, T2>(Expression<Func<T1, T2>> expression)
{
}
That will be able to be just a slight modification of your existing GetMethod implementation. T2 will be your delegate; you may need to cast it to Delegate, depending on how you use it.
Related
Occasionally I run into the problem of needing to execute a generic method without knowing its type.
I know I can do this each time using reflection, however I am trying to write a helper method:
public static object InvokeGeneric<T>(this T #this,
Expression<Func<T, object>> method,
Type genericType,
params object[] arguments)
{
// I think I know what to do here
// look at the expression tree, grab
// the method info, do the
// reflection in here, etc.
return null;
}
So that I can do this:
this._myService.InvokeGeneric(
e => e.MyGenericMethod, // interface IMyService { void MyGenericMethod<T>(T t); }
typeof(MyGenericType),
myArg);
However I am getting this error: Cannot convert method group 'XXX' to non-delegate type 'object'.
Without changing my calling syntax, how can I change my method signature of my helper method to do what I want?
EDIT:
I got it down to:
this._myService.InvokeGeneric<IMyService, object, MyArgType>(e => e.MyGenericMethod, typeof(MyGenericType), myArg);
The downside (besides extra typing) is that you'd need an overload for each generic variation of Func<> and Action<> that you'd want to support.
public static object InvokeGeneric<T, T1>(this object #this, Expression<Func<T, Action<T1>>> method, Type genericType, params object[] arguments)
{ }
public static object InvokeGeneric<T, T1, T2>(this object #this, Expression<Func<T, Action<T1, T2>>> method, Type genericType, params object[] arguments)
{ }
etc. I'm going to use that solution, but if anyone has something that meets the briefer syntax let me know and I'll accept it. Reading a bit about method groups made me realize my syntax is ambiguous, potentially, if there are overloads, meaning a strongly-typed one like this is probably better, anyway.
I'm trying to create an extension method for Moq where I can send in an expression to be used in an async return function. However this question is not really Moq specific. Here's what I have so far:
public static IReturnsResult<TMock> ReturnsAsync<TMock, TResult, T>(this IReturns<TMock, Task<TResult>> setup, Func<T, TResult> valueFunc) where TMock : class
{
return setup.Returns(Task.FromResult(valueFunc.Invoke(default(T))));
}
This is how I'm hoping to use it.
repo.Setup(x => x.FindAsync(It.IsAny<Expression<Func<T, bool>>>())).ReturnsAsync((Expression<Func<T, bool>> e) => context.GetSet<T>().FirstOrDefault(e));
Now I don't really know how all of this works and the thing I can't figure out is how to I get the expression passed on into the ReturnsAsync function so I can use it as the argument instead of the default(T) that I put there as a placeholder.
As expected the "e" variable here becomes null.
This method will do what you want:
public static IReturnsResult<TMock> ReturnsAsync<TMock, TResult, T>(
this IReturns<TMock, Task<TResult>> setup,
Func<Expression<Func<TResult, T>>, TResult> valueFunc)
where TMock : class
{
return setup.Returns<Expression<Func<TResult, T>>>(
e => Task.FromResult(valueFunc(e)));
}
Then use it like so:
repo.Setup(x => x.FindAsync(It.IsAny<Expression<Func<T, bool>>>()))
.ReturnsAsync<IRepository, int, bool>(e => context.GetSet<T>().FirstOrDefault(e));
Essentially, this version of ReturnsAsync takes a function that expects a predicate function (which is e) and returns a T. This allows you to then execute the predicate against your test data set (context.GetSet<T>.FirstOrDefault). Also, I used the overload of Returns that accepts a type parameter; this is used to forward the arguments from the Setup call to the function specified as the Returns argument.
Your version's signature only specified the predicate, so you had no way to execute it against your test data. You also had the T and TResult type parameters backwards in the valueFunc parameter's type.
I want to pass in a strongly types property to a method and use this propertyname as a string for mhy collection, so I found some code where I can pass my property strongly typed:
public static void Add<TObject, TProperty>(this NameValueCollection collection, Expression<Func<TObject, TProperty>> expression, string value)
{
var member = expression.Body as MemberExpression;
collection.Add(member.Member.Name, value);
}
This works and does what I want, but I was wondering how this exactly works. The part I am interested in is the generic arguments of the method (Add<Tobject, TProperty>) in combination with the Func expression. Can someone explain to me how this works? And why I can call this method like collection.Add((MyObject m) => m.FullName, "Martijn")? Why isn't it necessarly to use Add<MyObject, ???>(m => m.FullName, "Martijn")?
Update:
I now have my method refactored to this:
public static void Add<TObject>(this NameValueCollection collection, Expression<Func<TObject, string>> expression, string value)
{
var member = expression.Body as MemberExpression;
collection.Add(member.Member.Name, value);
}
Expression<T> is an expression tree that has the signature of delegate-type T. Expression trees are complex, but basically: instead of being a delegate that is the operation, this is an object-model that describes the operation, and that can be inspected to see how it is composed.
Thus, an Expression<Func<TObject,TProperty>> is an expression-tree representing something that accepts TObject parameter and returns TProperty result.
As for why you don't need to tell it the <MyObject, ???> manually: that is generic type inference, and is normal. Given a generic method, say:
void Foo<T>(T bar);
You can call that as:
Foo<string>("abc");
but you can also use:
Foo("abc");
The compiler will then inspect the parameters to see if it can resolve all of the generic type parameters - in this case, the "abc" is a string and pins T to being a string. If it can resolve all of them, you don't need to specify them.
In your example, the TObject is pinned because your lambda explicitly takes a MyObject, via (MyObject) m, and the TProperty is pinned to (presumably) a string, because m.FullName (presumably) returns a string. Since all the generic type parameters have been resolved automatically you do not need to specify the <...> manually.
Note that generic type inference only applies to generic methods (via the parameters), not to generic types.
I have a method which i want to convert to Extension Method
public static string GetMemberName<T>(Expression<Func<T>> item)
{
return ((MemberExpression)item.Body).Member.Name;
}
and calling it like
string str = myclass.GetMemberName(() => new Foo().Bar);
so it evaluates to str = "Bar"; // It gives the Member name and not its value
Now when i try to convert this to extension method by this
public static string GetMemberName<T>(this Expression<Func<T>> item)
{
return ((MemberExpression)item.Body).Member.Name;
}
and call it like
string str = (() => new Foo().Bar).GetMemberName();
Error says Operator '.' cannot be applied to operand of type 'lambda expression'
Where am I wrong?
There are really two things here, first, passing () => new Foo().Bar into the method that accepts Expression<Func<T>> treats the specified expression tree as a Expression<Func<T>>, but () => new Foo().Bar is not an Expression<Func<T>> on its own.
Second, in order to get your extension method to accept any lambda (such as you're supplying), you'd have to use the type that corresponds to any expression tree. But, as you may have already guessed based on the message ... to operand of type 'lambda expression' where you'd usually see the name of the type inside the quotes, that lambda expressions are treated specially by the language, making what you're trying to do, without casting first, impossible.
The way to invoke your extension method in extension method form would be (in the case that Bar is of type string)
((Expression<Func<string>>)(() => new Foo().Bar)).GetMemberName()`
which doesn't seem like it would be all that desirable.
Where am I wrong?
The compiler is telling you exactly what's wrong - you can't use . on a lambda expression.
The lambda expression doesn't have any particular type - it's just convertible to the expression tree.
A member-access expression (which is what you're trying to do) is only available in the forms
primary-expression . identifier type-argument-list(opt)
predefined-type . identifier type-argument-list(opt)
qualified-alias-member . identifier type-argument-list(opt)
... and a lambda expression isn't a primary expression.
Interestingly, this argument doesn't hold for an anonymous method expression, but for you still can't use a member access expression on that, either. Section 7.6.4 of the C# spec lists how a member access expression is bound, and the bulk of the options are either under "If E is a predefined-type or a primary-expression classified as a type" (which doesn't apply to anonymous methods) or "If E is a property access, variable, or value, the type of which is T" - but an anonymous method is an anonymous function, and as per section 7.15: "An anonymous function does not have a value or type in and of itself".
EDIT: You can still use extension methods on expression trees, you just can't use them directly on lambda expressions. So this will work:
Expression<Func<int>> expr = () => new Foo().Bar;
string name = expr.GetMemberName();
... but it's obviously not as useful. (Ditto with a cast as per mlorbetske's answer.)
To get typed expression, you will have to write it out. As others have said, there is no way compiler will automatically infer it from a lambda expression since a lambda expression can mean two things - either a delegate or an expression tree.
You can get the expression relatively simpler, by letting the compiler infer the type for you partially, like (from this answer):
public sealed class Lambda
{
public static Func<T> Func<T>(Func<T> func)
{
return func;
}
public static Expression<Func<T>> Expression<T>(Expression<Func<T>> expression)
{
return expression;
}
}
public sealed class Lambda<S>
{
public static Func<S, T> Func<T>(Func<S, T> func)
{
return func;
}
public static Expression<Func<S, T>> Expression<T>(Expression<Func<S, T>> expression)
{
return expression;
}
}
//etc, to cover more cases
Call it like:
var expr1 = Lambda.Expression(() => new Foo().Bar);
var expr2 = Lambda<string>.Expression(x => x.Length); //etc
Your options are:
Cast backward, to exact expression type and then call extension method on it
var name = ((Expression<Func<BarType>>)(() => new Foo().Bar)).GetMemberName();
looks ugly - cure worse than cause.
Get the expression first into a variable
Expression<Func<BarType>> expr = () => new Foo().Bar;
var name = expr.GetMemberName();
Slightly better, but still looks little off for a trivial thing.
Using the Lambda classes written above
var name = Lambda.Expression(() => new Foo().Bar).GetMemberName();
Even better. It's just a little less typing.
Your first pattern, which I think is the best you can get as far as readability goes
I dont think you can improve upon that considering C# rules related to lambda expressions. That said I think few improvements can be made.
First, extend the functionality to other lambda expression types. You would need more than Func<T> types to handle all cases. Decide what are the expression types you have to handle. For instance if you have a Func<S, T> type (as in your question - Bar on Foo), it looks better. Compare this
myclass.GetMemberName(() => new Foo().Bar);
with
myclass.GetMemberName<Foo>(x => x.Bar);
I would say these overloads would do:
//for static methods which return void
public static string GetMemberName(Expression<Action> expr);
//for static methods which return non-void and properties and fields
public static string GetMemberName<T>(Expression<Func<T>> expr);
//for instance methods which return void
public static string GetMemberName<T>(Expression<Action<T>> expr);
//for instance methods which return non-void and properties and fields
public static string GetMemberName<S, T>(Expression<Func<S, T>> expr);
Now these can be used not just in the cases mentioned in comments, surely there are overlapping scenarios. For instance, if you already have instance of Foo, then its easier to call the second overload (Func<T>) overload for name of property Bar, like myclass.GetMemberName(() => foo.Bar).
Secondly, implement a GetMemberName functionality common to all these overloads. An extension method on Expression<T> or LambdaExpression would do. I prefer the latter so that you get to call it even in non-strongly typed scenarios. I would write it like this, from this answer:
public static string GetMemberName(this LambdaExpression memberSelector)
{
Func<Expression, string> nameSelector = null;
nameSelector = e => //or move the entire thing to a separate recursive method
{
switch (e.NodeType)
{
case ExpressionType.Parameter:
return ((ParameterExpression)e).Name;
case ExpressionType.MemberAccess:
return ((MemberExpression)e).Member.Name;
case ExpressionType.Call:
return ((MethodCallExpression)e).Method.Name;
case ExpressionType.Convert:
case ExpressionType.ConvertChecked:
return nameSelector(((UnaryExpression)e).Operand);
case ExpressionType.Invoke:
return nameSelector(((InvocationExpression)e).Expression);
case ExpressionType.ArrayLength:
return "Length";
default:
throw new Exception("not a proper member selector");
}
};
return nameSelector(memberSelector.Body);
}
Lastly, GetMemberName is not a good name if you're to call it non-extension way. expression.GetMemberName() sounds more logical. Member.NameFrom<int>(x => x.ToString()) or MemberName.From<string>(x => x.Length) etc are more descriptive names for static calls.
So overall the class might look like:
public static class Member
{
public static string NameFrom(Expression<Action> expr)
{
return expr.GetMemberName();
}
public static string NameFrom<T>(Expression<Func<T>> expr)
{
return expr.GetMemberName();
}
public static string NameFrom<T>(Expression<Action<T>> expr)
{
return expr.GetMemberName();
}
public static string NameFrom<T>(Expression<Func<T, object>> expr)
{
return expr.GetMemberName();
}
}
And usage:
var name1 = Member.NameFrom(() => Console.WriteLine());
var name2 = Member.NameFrom(() => Environment.ExitCode);
var name3 = Member.NameFrom<Control>(x => x.Invoke(null));
var name4 = Member.NameFrom<string>(x => x.Length);
Most concise and clean.
For properties and fields, it can be transformed to an anonymous class and then using reflection the member name can be read, as shown here.
public static string GetMemberName<T>(T item) where T : class
{
if (item == null)
return null;
return typeof(T).GetProperties()[0].Name;
}
Call it like
var name = GetMemberName(new { new Foo().Bar });
It's faster, but has certain quirks, like not very refactor friendly, and doesnt help in case of methods as members. See the thread..
Of all I prefer 4.
How can I supply a func to a method, so I could write something like:
MethodTest(a => a.IsAltTagAvailable);
Where the signature of this method takes a func which returns an object (say HtmlImage) when the condition is met (basically just a predicate).
Edit: I need to pass the type I will be working on as T (Parameter). I forgot to do this, how clumsy!
Thanks
A predicate tends to return bool, not an object. What are you going to return when the condition isn't met? Given your example, you don't really mean the function returns an object - you mean it takes an object and returns a bool.
Note that if you're going to have a parameter in the lambda expression, you'll need to use a delegate which takes parameters too.
We really need more information before giving a definitive answer, but you might want something like:
void MethodTest(Func<HtmlImage, bool> predicate)
or
void MethodTest(Predicate<HtmlImage> predicate)
(Personally I like the descriptive nature of using a named delegate, but others prefer to use Func/Action for almost everything.)
That's assuming that the type of input is fixed. If not, you might want to make it a generic method:
void MethodTest<T>(Predicate<T> predicate)
void MethodTest(Func<HtmlImage> func) {
}
void MethodTest(Func<HtmlImage, object> func)
{
}
HtmlImage is the argument of the function (x), object the return value, you could take the concrete type if you want to specify it.
void MethodTest(Func<HtmlImage, bool> func)
Which is a predicate:
void MethodTest(Predicate<HtmlImage> func)
To make it fully generic, replace HtmlImage with a generic argument:
void MethodTest<T>(Predicate<T> func)
public void MethodTest(Func<HtmlImage> delegate)
{
//do what you want
}
OR:
public delegate HtmlImageTagHandler(HtmlImage image);
public HtmlImage MethodTest(HtmlImageTagHandler handler, HtmlImage image)
{
return handler(image) == true ? image : null;
}
use:
MethodTest(a => a.IsAltTagAvailable, a);