C# 优化用于MVC InputFor的lambda表达式时出现模板错误

C# 优化用于MVC InputFor的lambda表达式时出现模板错误,c#,asp.net-mvc,lambda,linq-expressions,C#,Asp.net Mvc,Lambda,Linq Expressions,在我的应用程序中,我有几个(>10)地方有这样的模型: public interface IOptionList { string Name; bool Checked; } public class Option : IOptionList { } public class MyModel { public Option[] Options = { new Option { Name = "Option 1", Checked = fals

在我的应用程序中,我有几个(>10)地方有这样的模型:

public interface IOptionList
{
    string Name;
    bool Checked;
}

public class Option : IOptionList { }

public class MyModel
{
    public Option[] Options = 
    {
        new Option { Name = "Option 1", Checked = false }
    };

    // etc... for many more implementations of IOptionList
}
@Html.CheckBoxFormGroupFor(x => x.Options, Model.Options)
public static CheckBoxFormGroupFor<TModel, TItem>(this HtmlHelper<TModel>html,
    Expression<Func<TModel, TItem[]>> expression, TItem[] values)
{
    var sb = new StringBuilder();

    for (int i = 0; i < values.Length; i++)
    {
        var indexExpression = Expression.ArrayIndex(expression.Body, Expression.Constant(i));
        var checkedAccessExpression = Expression.Property(indexExpression, typeof(ICheckboxList), "Checked");
        var lambda = Expression.Lambda<Func<TModel, bool>>(checkedAccessExpression, Expression.Parameter(typeof(TModel)));
        var cbx = html.CheckBoxFor(x => lambda.Compile()(x));
        var lbl = html.LabelFor(x => lambda.Compile()(x), values[i].Name);

        var div = new TagBuilder("div");
        div.InnerHtml = $"{cbx}{lbl}";
        sb.Append(div);
    }
    return new HtmlString(sb.ToString());
}
这些用于在视图中生成复选框列表,如下所示:

@for (int i = 0; i < Model.Options.Length; i++)
{
    <div>
        @Html.CheckBoxFor(x => x.Options[i].Checked)
        @Html.LabelFor(x => x.Options[i].Checked, Model.Options[i].Name)
    </div>
}
我目前的尝试如下所示:

public interface IOptionList
{
    string Name;
    bool Checked;
}

public class Option : IOptionList { }

public class MyModel
{
    public Option[] Options = 
    {
        new Option { Name = "Option 1", Checked = false }
    };

    // etc... for many more implementations of IOptionList
}
@Html.CheckBoxFormGroupFor(x => x.Options, Model.Options)
public static CheckBoxFormGroupFor<TModel, TItem>(this HtmlHelper<TModel>html,
    Expression<Func<TModel, TItem[]>> expression, TItem[] values)
{
    var sb = new StringBuilder();

    for (int i = 0; i < values.Length; i++)
    {
        var indexExpression = Expression.ArrayIndex(expression.Body, Expression.Constant(i));
        var checkedAccessExpression = Expression.Property(indexExpression, typeof(ICheckboxList), "Checked");
        var lambda = Expression.Lambda<Func<TModel, bool>>(checkedAccessExpression, Expression.Parameter(typeof(TModel)));
        var cbx = html.CheckBoxFor(x => lambda.Compile()(x));
        var lbl = html.LabelFor(x => lambda.Compile()(x), values[i].Name);

        var div = new TagBuilder("div");
        div.InnerHtml = $"{cbx}{lbl}";
        sb.Append(div);
    }
    return new HtmlString(sb.ToString());
}
public static CheckBoxFormGroupFor(此HtmlHelperhtml,
表达式,滴度[]值)
{
var sb=新的StringBuilder();
for(int i=0;ilambda.Compile()(x));
var lbl=html.LabelFor(x=>lambda.Compile()(x),值[i].Name);
var div=新标记生成器(“div”);
div.InnerHtml=$“{cbx}{lbl}”;
某人追加(div);
}
返回新的HtmlString(sb.ToString());
}
据我所知,它扩展了初始lambda表达式
x=>x.Options
,以在正确的数组索引处访问对象的正确属性,但是这给了我一个消息模板错误

模板只能用于字段访问、属性访问、一维数组索引或单参数自定义索引器表达式

据我所知,我只做了一个单D数组索引,然后是属性访问,所以我不确定为什么会看到这个。我以前试过
var cbx=html.CheckBoxFor(lambda)
但这不起作用,因为参数
x
仅在视图范围内定义


假设我想要的是可能的,有人能帮助我实现吗?我不习惯用这种方式操作
表达式。

你很接近了。直接使用
lambda
变量

var cbx = html.CheckBoxFor(lambda);
var lbl = html.LabelFor(lambda, values[i].Name);
这确实是正确的方法。只需确保您编写的lambda表达式使用与
表达式
参数相同的参数(因为它绑定到新表达式中使用的主体),即此处

var lambda = Expression.Lambda<Func<TModel, bool>>(
    checkedAccessExpression,
    Expression.Parameter(typeof(TModel)));

你很接近。直接使用
lambda
变量

var cbx = html.CheckBoxFor(lambda);
var lbl = html.LabelFor(lambda, values[i].Name);
这确实是正确的方法。只需确保您编写的lambda表达式使用与
表达式
参数相同的参数(因为它绑定到新表达式中使用的主体),即此处

var lambda = Expression.Lambda<Func<TModel, bool>>(
    checkedAccessExpression,
    Expression.Parameter(typeof(TModel)));

不清楚您想要传递给方法的是什么-您当前正在两个参数中传递相同的模型。在任何情况下,为什么不使用
EditorTempate
,而只使用
@Html.EditorFor(m=>m.Options)
(错误是因为
x=>lambda.Compile()(x)
这没有任何意义,但同样,不确定您试图用它实现什么您可以用一半的代码完成所有这一切,签名应该只是
公共静态CheckBoxFormGroupFor(此htmlhelp html,Expression Expression)
如果您总是传递一个
IOptionList
数组,我考虑使用
IEnumerable
但是为了索引列表,我需要调用
ToArray
Expression.ArrayIndex
仅适用于数组)MVC的*for方法的模板不能包含方法调用——这会破坏模型绑定。你可以让它工作得很好(就像使用ModelMetadata的内置HtmlHelper方法一样)。但是仍然不清楚为什么你不为
选项的类型创建
EditorTemplate
(只包含
@Html.CheckBoxFor(x=>x.Checked)
@Html.LabelFor(x=>x.Checked,Model.Name)
),只需使用
@Html.EditorFor(m=>m.Options)
不清楚您想要传递给方法的是什么-您当前在两个参数中传递的是相同的模型。无论如何,为什么不使用
EditorTempate
,而只使用
@Html.EditorFor(m=>m.Options)
(错误是因为
x=>lambda.Compile()(x)
这没有任何意义,但同样,不确定您试图用它实现什么您可以用一半的代码完成所有这一切,签名应该只是
公共静态CheckBoxFormGroupFor(此htmlhelp html,Expression Expression)
如果您总是传递一个
IOptionList
数组,我考虑使用
IEnumerable
但是为了索引列表,我需要调用
ToArray
Expression.ArrayIndex
仅适用于数组)MVC的*for方法的模板不能包含方法调用——这会破坏模型绑定。你可以让它工作得很好(就像使用ModelMetadata的内置HtmlHelper方法一样)。但是仍然不清楚为什么你不为
选项的类型创建
EditorTemplate
(只包含
@Html.CheckBoxFor(x=>x.Checked)
@Html.LabelFor(x=>x.Checked,Model.Name)
),只需使用
@Html.EditorFor(m=>m.Options)
expression,谢谢!我不知道
expression。Paramaters
存在,这现在很有意义。精彩,谢谢!我不知道
expression。Paramaters
存在,现在很有意义。