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-typeT. 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 acceptsTObjectparameter and returnsTPropertyresult.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:You can call that as:
but you can also use:
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 astringand pinsTto being astring. If it can resolve all of them, you don’t need to specify them.In your example, the
TObjectis pinned because your lambda explicitly takes aMyObject, via(MyObject) m, and theTPropertyis pinned to (presumably) astring, becausem.FullName(presumably) returns astring. 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.