Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-mvc/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/redis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何创建一个接受多个lambda表达式作为参数的方法?_C#_Asp.net Mvc_Linq_Lambda - Fatal编程技术网

C# 如何创建一个接受多个lambda表达式作为参数的方法?

C# 如何创建一个接受多个lambda表达式作为参数的方法?,c#,asp.net-mvc,linq,lambda,C#,Asp.net Mvc,Linq,Lambda,我正在尝试创建自己的扩展方法,可以接受任意数量的lambda表达式,但每当我添加多个表达式时,它似乎都会阻塞 方法如下: public static MvcHtmlString _RouteButton<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, string label, string controller, string action, params Expression<Func<TMod

我正在尝试创建自己的扩展方法,可以接受任意数量的lambda表达式,但每当我添加多个表达式时,它似乎都会阻塞

方法如下:

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;
}
public static MvcHtmlString\u RouteButton(此HtmlHelper HtmlHelper、字符串标签、字符串控制器、字符串操作、参数表达式[]参数)
{
var测试=参数;
返回MvcHtmlString.Empty;
}
以下是成功调用它的标记:

<%: Html._RouteButton("details", "Health", "SystemDetails", m=>m.Id)%>
m.Id)%%>
以下是显示错误的标记:

<%: Html._RouteButton("details", "Health", "SystemDetails", m=>m.Id, m=>m.Status)%>
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
    }
}
使用系统;
P类
{
静态void M(params Func[]p{}
静态void N(整数i,字符串s,十进制m)
{
M(()=>i,()=>s);//失败
M(()=>i,()=>s.Length);//成功
M(()=>i,()=>M);//成功
}
}
现在清楚你的程序失败的原因了吗

在我的程序中,每个调用都试图推断R。在第一个调用中,R被推断为int和string,因此推断失败,因为没有同时为int和string的类型。在第二种情况下,R被推断为int,并且。。。又是int!这会成功,因为int匹配所有边界。在第三种情况下,R被推断为int和decimal,这是成功的,因为每个int都可以隐式转换为decimal,所以decimal是一个很好的推断

Id和状态可能是类型不兼容的属性。如果要执行此操作,则推断的类型之一必须是最佳类型


请注意,C#从不说“哦,我看到你推断了狗、猫和鱼的界限,所以我猜你指的是动物”。C#宁说“狗、猫或鱼都不是最好的束缚,所以我不知道你的意思;请明确说明”

Eric Lippert的回答解释了问题所在。我将添加实际解决方法:您很可能不需要lambda来返回属性的类型,您只需要获取表达式树来检查属性。因此,您可以将类型从
Func
更改为
Func
(并删除
TProperty
类型参数)。由于C#中的所有普通类型都可以隐式转换为
对象
,因此您的代码可以通过此更改编译并运行良好

我想在网站上获取此信息,以防有人尝试类似的操作

该代码构建了一个路由表单。为此,它需要属性的名称及其

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 + "' />");
    }
}
publicstaticvoid\u RouteButton(此HtmlHelper HtmlHelper、字符串文本、字符串控制器、字符串操作、参数表达式[]参数)
{
使用(htmlHelper.BeginRouteForm(“默认”,新的{controller=controller,action=action}))
{
foreach(参数中的表达式p)
{
请原谅我;
开关(p.Body.NodeType)
{
大小写表达式类型。转换:
case ExpressionType.ConvertChecked:
var ue=作为一元表达式的p.体;
me=((ue!=null)?ue.Operand:null)作为MemberExpression;
打破
违约:
me=作为成员表达式的主体;
打破
}
字符串名称=me.Member.name;
字符串值=p.Compile()(htmlhelp.ViewData.Model).ToString();
HttpContext.Current.Response.Write(htmlhelp.Hidden(name,value.ToHtmlString());
}
HttpContext.Current.Response.Write(“”);
}
}
@eric lippert根据您的示例解释了“为什么它不起作用”。每个表达式中传递的属性类型不同

将扩展方法的签名更改为仅指定TModel,因为泛型将帮助解决此问题。此外,还可以使用specifyobject代替expression函数的TProperty

扩展方法

public static MvcHtmlString _RouteButton<TModel>(this HtmlHelper<TModel> htmlHelper, 
                                                 params Expression<Func<TModel, object>>[] parameters)
{
    var test = parameters;
    return MvcHtmlString.Empty;
}
public static MvcHtmlString\u RouteButton(此HtmlHelper HtmlHelper,
参数表达式[]参数)
{
var测试=参数;
返回MvcHtmlString.Empty;
}
ASP/Razor

<%: Html._RouteButton(m=>m.Id, m=>m.Status)%>
@Html._RouteButton(m=>m.Id, m=>m.Status)
m.Id,m=>m.Status)%%>
@Html._路由按钮(m=>m.Id,m=>m.Status)

Id和状态的类型是什么?与其使用多个lambda来获取多个参数,您是否可以只使用一个参数来返回一个新的匿名对象以及必要的字段
new{id=m.id,status=m.status})%%>
@ShaneA您不能这样做,因为如果涉及匿名类型,您无法为参数定义类型。Shane,我实际上有一个覆盖可以这样做,但为了简单起见,我想传递lambda表达式。我可以看到失败的模式,但类型似乎应该是Func,而不是string、int或decimal。为什么.Net会进行比方法签名更严格的验证?@Nathaniel:R不是一种类型。R是必须用类型填充的占位符。(与参数不是值的方式相同,参数是必须提供值的位置,称为参数。)编译器告诉您,它无法计算出要用什么类型替换R。@Nathaniel:这是编译时间限制,而不是运行时错误。这与编组无关。这样看。当您有一个方法
M
并调用它时,需要提供一个类型参数。您需要说
M
,这与创建新列表时需要说
List
的方式相同。它必须是一个列表的东西。方法必须是某种东西的方法。现在,出于礼貌,如果您省略了
,编译器将尝试猜测您的意思