How to create a method that takes multiple lambda expressions as parameters?

I am trying to create my own extension method that can accept any number of lambda expressions, but it seems that it suffocates at any time when I add more than one expression.

Here is a way:

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 for that error:

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

Here is the error:

Type arguments for a method cannot be taken out of use. Try explicitly specifying type arguments

Any help is appreciated. Thanks!

+4
source share
4 answers

I wanted to get this on the site if someone tried something like this.

The code creates a route form. To do this, he needs the name of the property and its value .

 public static void _RouteButton<TModel>(this HtmlHelper<TModel> htmlHelper, string text, string controller, string action, params Expression<Func<TModel, object>>[] parameters) { using (htmlHelper.BeginRouteForm("Default", new { controller = controller, action = action })) { foreach (Expression<Func<TModel, object>> p in parameters) { MemberExpression me; switch (p.Body.NodeType) { case ExpressionType.Convert: case ExpressionType.ConvertChecked: var ue = p.Body as UnaryExpression; me = ((ue != null) ? ue.Operand : null) as MemberExpression; break; default: me = p.Body as MemberExpression; break; } string name = me.Member.Name; string value = p.Compile()(htmlHelper.ViewData.Model).ToString(); HttpContext.Current.Response.Write(htmlHelper.Hidden(name, value).ToHtmlString()); } HttpContext.Current.Response.Write("<input type='submit' value='" + text + "' />"); } } 
+1
source

Let it be simplified:

 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 it’s clear why your program crashes?

In my program, every call tries to make a conclusion R. In the first call to R, both int and string are called, and therefore the output is not executed, because there is no type that is both int and string. In the second, R is defined as int and ... int again! which succeeds because int matches all bounds. In the third, R is defined as int and decimal, which succeeds because each int can be implicitly converted to decimal, so decimal is good output.

Identifier and status are probably properties with incompatible types. If you want to do this, then one of the types that should be selected should be the best type.

Note that C # never says "oh, I see that you have drawn the boundaries of the dog, cat and fish, so I think you had in mind the animal." C # rather says that "none of the Dogs, Cats or Pisces is certainly the best border, so I don’t know what you had in mind, please state it explicitly."

+8
source

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

+4
source

@ eric-lippert explained β€œwhy this will not work” based on your example. The types of properties passed in each expression do not match.

Change the signature of the extension method only to the TModel specification, as the general way will help solve the problem. In addition, defineobject instead of TProperty for the expression function.

Extension method

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

ASP / Razor

 <%: Html._RouteButton(m=>m.Id, m=>m.Status)%> @Html._RouteButton(m=>m.Id, m=>m.Status) 
-1
source

All Articles