![](/img/trans.png)
[英]How can I write a method that accepts a lambda expression where the number of parameters to the lambda expression is unknown?
[英]How do I make a method that accepts multiple lambda expressions as parameters?
我正在尝试创建自己的可以接受任意数量的lambda表达式的Extension方法,但是当我添加多个表达式时,它似乎会窒息。
这是方法:
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;
}
这是成功调用它的标记:
<%: Html._RouteButton("details", "Health", "SystemDetails", m=>m.Id)%>
这是错误的标记:
<%: Html._RouteButton("details", "Health", "SystemDetails", m=>m.Id, m=>m.Status)%>
这是错误:
无法从用法中推断出方法的类型参数。 尝试显式指定类型参数
任何帮助表示赞赏。 谢谢!
让我们简化一下:
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
}
}
现在很清楚为什么你的程序失败了?
在我的程序中,每次调用都会尝试推断R.在第一次调用中,R被推断为int和string,因此推理失败,因为没有int和string类型。 在第二个,R被推断为int和... int再次! 这是成功的,因为int匹配所有边界。 在第三个中,R被推断为int和decimal,这是成功的,因为每个int都可以隐式转换为decimal,因此decimal是一个很好的推理。
Id和Status可能是具有不兼容类型的属性。 如果要执行此操作,则推断的其中一种类型必须是最佳类型 。
请注意,C#从不说“哦,我看到你推断出狗,猫和鱼的界限,所以我猜你的意思是动物”。 C#反而说“狗,猫或鱼都不是最好的约束,所以我不知道你的意思;请明确说明”。
Eric Lippert的答案解释了问题所在。 我将添加如何实际解决它:您很可能不需要lambda来返回属性的类型,您只是想获取表达式树来检查属性。 因此,您可以做的是将类型从Func<TModel, TProperty>
更改为Func<TModel, object>
(并删除TProperty
类型参数)。 由于C#中的所有普通类型都可以隐式转换为object
,因此您的代码将通过此更改进行编译和运行
我想在网站上得到这个,以防有人尝试类似的东西。
代码构建路由表单。 要做到这一点,它需要属性的名称及其值 。
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 + "' />");
}
}
@ eric-lippert根据你的例子解释了“为什么它不起作用”。 每个表达式中传递的属性类型不相同。
将扩展方法的签名更改为仅指定TModel,因为通用将有助于解决问题。 另外,为表达式函数指定对象代替TProperty。
扩展方法
public static MvcHtmlString _RouteButton<TModel>(this HtmlHelper<TModel> htmlHelper,
params Expression<Func<TModel, object>>[] parameters)
{
var test = parameters;
return MvcHtmlString.Empty;
}
ASP /剃刀
<%: Html._RouteButton(m=>m.Id, m=>m.Status)%>
@Html._RouteButton(m=>m.Id, m=>m.Status)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.