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.
Related
In this answer, I wrote a LINQ extension that utilizes the following delegate, so I can pass in a function with an out variable, such as int.TryParse:
public delegate bool TryFunc<TSource, TResult>(TSource source, out TResult result);
public static IEnumerable<TResult> SelectTry<TSource, TResult>(
this IEnumerable<TSource> source, TryFunc<TSource, TResult> selector)
{
foreach (TSource item in source)
{
TResult result;
if (selector(item, out result))
{
yield return result;
}
}
}
In order to use this extension, I have to explicitly specify the <string, int> types like so:
"1,2,3,4,s,6".Split(',').SelectTry<string, int>(int.TryParse); // [1,2,3,4,6]
I want to remove <string, int>, similar to how we can call .Select(int.Parse) without specifying <int>, but when I do, I get the following error:
The type arguments for method 'LINQExtensions.SelectTry(IEnumerable, LINQExtensions.TryFunc)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
My question is, why can't the types be inferred? My understanding is that the compiler should know the signatures of int.TryParse and subsequently the TryFunc delegate at compile time.
It can't be inferred because only one of those arguments fits and that's the string. The 2nd parameter is the out int and that cannot be specified in the generic arguments which is why it is saying the arguments cannot be inferred.
The only way to call SelectTry without specifying arguments is by declaring your delegate somewhere that points to int.TryParse and then passing it in as your parameter.
I know this isn't what you want, this is the only way I know of getting around specifying the arguments.
TryFunc<string, int> foo = int.TryParse;
var s = "1,2,3,4,s,6".Split(',').SelectTry(foo);
Remember, in order to pass in methods as delegates, the parameters must match 1:1. int.TryParse matches TryFunc, but it does not match SelectTry
I'd like to write an overload for Includes that would allow me to do something like db.Transactions.Include(t => t.Customer, t => t.Order) rather than needing to do db.Transactions.Include(t => t.Customer).Include(t => t.Order). Here's my attempt:
public static IQueryable<T> Include<T, TProperty>(this IQueryable<T> source, params Expression<Func<T, TProperty>>[] paths) {
foreach (var path in paths) {
source = QueryableExtensions.Include(source, path);
}
return source;
}
But when I try to use it, I get an error that says "The type arguments for the method cannot be inferred from the usage." Is what I'm trying to do possible?
Your method won't work as you are expecting it to. Currently, your method will expect that every expression is returning the same type, which will not work if you pass selectors for class properties of different type.
To properly handle various types, you need to change the signature of the method by removing type parameter TProperty and using Expression<Func<T, object>> as argument type.
Resulting signature should be as follows:
public static IQueryable<T> Include<T>(this IQueryable<T> source, params Expression<Func<T, object>>[] paths)
This will allow you to pass collection of various expressions to the method.
You may suspect, that it will cause problems, because you are implicitly converting the property to object, but it won't be an issue. If you examine the source code of QueryableExtensions.Include (and moving deeper to DbHelpers.TryParsePath), you will see that conversion is removed before expression is converted to string.
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 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.
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.