Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I make a method that accepts multiple lambda expressions as parameters?

I'm trying to make my own Extension method that can take any number of lambda expressions, but It seems to choke any time I add more than one expression.

Here is the method:

public static MvcHtmlString _RouteButton<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, string label, string controller, string action, params Expression<Func<TModel, TProperty>>[] parameters)
{
   var test = parameters;
   return MvcHtmlString.Empty;
}

Here is the markup that calls it successfully:

<%: Html._RouteButton("details", "Health", "SystemDetails", m=>m.Id)%>

Here is the markup that errors:

<%: Html._RouteButton("details", "Health", "SystemDetails", m=>m.Id, m=>m.Status)%>

Here is the error:

The type arguments for method cannot be inferred from the usage. Try specifying the type arguments explicitly

Any help is appreciated. Thanks!

like image 423
N-ate Avatar asked Dec 16 '22 14:12

N-ate


2 Answers

Let's simplify:

using System;
class P
{
    static void M<R>(params Func<R>[] p) {}
    static void N(int i, string s, decimal m)
    {
        M(()=>i, ()=>s); // fails
        M(()=>i, ()=>s.Length); // succeeds
        M(()=>i, ()=>m); // succeeds
    }
}

Now is it clear why your program fails?

In my program each call attempts to infer R. In the first call, R is inferred to be both int and string, and therefore inference fails because there is no type that is both int and string. In the second, R is inferred to be int and... int again! which succeeds because int matches all bounds. In the third, R is inferred to be int and decimal, which succeeds, because every int can be implicitly converted to decimal, so decimal is a good inference.

Id and Status are probably properties with incompatible types. If you want to do this then one of the types inferred must be the best type.

Note that C# never says "oh, I see you inferred bounds of Dog, Cat and Fish, so I guess you meant Animal". C# rather says "none of Dog, Cat or Fish are clearly the best bound, so I don't know what you meant; please specify it explicitly".

like image 155
Eric Lippert Avatar answered Mar 30 '23 00:03

Eric Lippert


Eric Lippert's answer explains what the problem is. I would add how to actually solve it: you most likely don't need the lambda to return the type of the property, you just want to get the expression tree to examine the properties. So, what you can do is to change the type from Func<TModel, TProperty> to Func<TModel, object> (and remove the TProperty type parameter). Since all normal types in C# are implicitly convertible to object, your code will compile and run fine with this change

like image 36
svick Avatar answered Mar 30 '23 01:03

svick