- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个静态的通用 FormBuilder HTML 辅助方法(HTMLHelper 类的扩展方法),它采用 View 模型类型的通用参数,然后,当从数据库传递一个或多个字符串属性名称时,生成一个 HTML 表单ASP.NET MVC 5.1 与 .NET 4.5。
我有一个公共(public)方法来生成表单,还有单独的私有(private)方法来生成表单中的“模块”部分,然后在其中呈现每个字段。类型参数沿着这条链从上到下传递。
在“RenderField”方法中,我使用代码创建了一个类型化的 HtmlHelper-
var typedHelper = helper as HtmlHelper<TModel>;
其中helper是RenderForm方法中扩展的HtmlHelper
然后我使用代码创建一个表达式-
var modelType = typeof(TModel);
...
var modelProperty = modelType.GetProperty(field.PropertyName);
if (modelProperty == null)
{
Elmah.ErrorSignal.FromCurrentContext().Raise(new ArgumentException(string.Format("Model {0} does not contain property {1}", modelType.Name, field.PropertyName)));
return null;
}
var modelPropertyType = modelProperty.PropertyType;
var parameter = Expression.Parameter(modelType, "m");
var property = Expression.Property(parameter, field.PropertyName);
var expression = Expression.Lambda<Func<TModel, object>>(property, parameter);
稍后我可以使用它来创建 EditorFor、DisplayFor 或 ValidationMessageFor,如下所示-
fieldContainer.InnerHtml += typedHelper.EditorFor(expression);
fieldContainer.InnerHtml += typedHelper.ValidationMessageFor(expression);
这适用于字符串编辑器,但如果我尝试可以为 null 的日期时间,则会出现错误 -
Expression of type 'System.Nullable`1[System.DateTime]' cannot be used for return type 'System.Object'
如果我尝试通过更改以下行将属性转换为对象,正如我在 Jon Skeet 的回答中看到的那样-
var expression = Expression.Lambda<Func<TModel, object>>(Expression.Convert(property, typeof(object)), parameter);
并将编辑器代码更改为 -
var compiledExpression = expression.Compile()(model);
fieldContainer.InnerHtml += typedHelper.EditorFor(compiledExpression);
fieldContainer.InnerHtml += typedHelper.ValidationMessageFor(compiledExpression);
我收到无法从用法推断类型参数的错误消息。
如果我将返回类型更改为“动态”,那么它会显示“无法动态分派(dispatch)扩展方法”。
我不能将“modelPropertyType”指定为泛型方法的返回参数——大概是因为它不能保证在编译时是具体类型。
有什么方法可以在运行时动态地将表达式的返回类型指定为属性的返回类型,以便我可以使用 ASP.NET MVC 提供的 EditorFor 辅助方法?
最佳答案
假设您使用 TModel
的通用参数创建了一个辅助函数和 TProperty
,您可以在其中构建用于编辑单个模型属性的 html。此助手将收到 HtmlHelper<TModel>
的实例和一个 PropertyInfo
它将创建适当的 lambda 表达式,类似于 EditorFor
要求。助手可能看起来像这样:
private static MvcHtmlString GetPropertyEditor<TModel, TProperty>(HtmlHelper<TModel> htmlHelper, PropertyInfo propertyInfo)
{
//Get property lambda expression like "m => m.Property"
var modelType = typeof(TModel);
var parameter = Expression.Parameter(modelType, "m");
var property = Expression.Property(parameter, propertyInfo.Name);
var propertyExpression = Expression.Lambda<Func<TModel, TProperty>>(property, parameter);
//Get html string with label, editor and validation message
var editorContainer = new TagBuilder("div");
editorContainer.AddCssClass("editor-container");
editorContainer.InnerHtml += htmlHelper.LabelFor(propertyExpression);
editorContainer.InnerHtml += htmlHelper.EditorFor(propertyExpression);
editorContainer.InnerHtml += htmlHelper.ValidationMessageFor(propertyExpression);
return new MvcHtmlString(editorContainer.ToString());
}
该助手将生成一个容器 div <div class="editor-container"></div>
,其内部 html 将包含标签、编辑器和验证消息。
如您所见,助手仍然需要您提供属性的泛型类型 TProperty
,当您使用反射循环遍历每个属性时,您将不会拥有它。但是,您也可以使用反射为每个属性调用此助手:
foreach (var propertyInfo in modelType.GetProperties())
{
var openMethod = typeof(HtmlExtensions).GetMethod("GetPropertyEditor", BindingFlags.Static | BindingFlags.NonPublic);
var genericMethod = openMethod.MakeGenericMethod(modelType, propertyInfo.PropertyType);
var editorHtml = genericMethod.Invoke(null, new object[] { htmlHelper, propertyInfo });
//add editorHtml to the form
}
因此您可以创建自己的 HtmlHelper 扩展方法,为给定模型生成表单:
public static MvcHtmlString RenderForm<TModel>(this HtmlHelper<TModel> htmlHelper)
{
var modelType = typeof(TModel);
var form = new TagBuilder("form");
foreach (var propertyInfo in modelType.GetProperties())
{
//call generic GetPropertyEditor<TModel, TProperty> with the type of this property
var openMethod = typeof(HtmlExtensions).GetMethod("GetPropertyEditor", BindingFlags.Static | BindingFlags.NonPublic);
var genericMethod = openMethod.MakeGenericMethod(modelType, propertyInfo.PropertyType);
var editorHtml = genericMethod.Invoke(null, new object[] { htmlHelper, propertyInfo });
//add the html to the form
form.InnerHtml += editorHtml;
}
return new MvcHtmlString(form.ToString());
}
给定如下模型:
public class RegisterViewModel
{
[Required]
[Display(Name = "User name")]
public string UserName { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[System.ComponentModel.DataAnnotations.Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
public DateTime? RegisterDate { get; set; }
}
你可以像这样在 View 中使用它:
@Html.RenderForm()
它将生成以下 html:
<form>
<div class="editor-container">
<label for="UserName">User name</label>
<input class="text-box single-line" data-val="true" data-val-required="The User name field is required." id="UserName" name="UserName" type="text" value="" /><span class="field-validation-valid" data-valmsg-for="UserName" data-valmsg-replace="true"></span>
</div>
<div class="editor-container">
<label for="Password">Password</label>
<input class="text-box single-line password" data-val="true" data-val-length="The Password must be at least 6 characters long." data-val-length-max="100" data-val-length-min="6" data-val-required="The Password field is required." id="Password" name="Password" type="password" value="" /><span class="field-validation-valid" data-valmsg-for="Password" data-valmsg-replace="true"></span>
</div>
<div class="editor-container">
<label for="ConfirmPassword">Confirm password</label>
<input class="text-box single-line password" data-val="true" data-val-equalto="'Confirm password' and 'Password' do not match." data-val-equalto-other="*.Password" id="ConfirmPassword" name="ConfirmPassword" type="password" value="" /><span class="field-validation-valid" data-valmsg-for="ConfirmPassword" data-valmsg-replace="true"></span>
</div>
<div class="editor-container">
<label for="RegisterDate">RegisterDate</label>
<input class="text-box single-line" data-val="true" data-val-date="The field RegisterDate must be a date." id="RegisterDate" name="RegisterDate" type="datetime" value="" /><span class="field-validation-valid" data-valmsg-for="RegisterDate" data-valmsg-replace="true"></span>
</div>
</form>
你对生成的html的结构、类名、属性等会有不同的要求,但我希望这可以帮助你完成你正在编写的FormBuilder!
关于c# - 动态表达返回类型的 Lambda 表达式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24240598/
可以使用 lambda 和函数创建有序对(Lisp 中的缺点),如 Use of lambda for cons/car/cdr definition in SICP 所示。 它也适用于 Python
我正在尝试从另一个调用一个 AWS lambda 并执行 lambda 链接。这样做的理由是 AWS 不提供来自同一个 S3 存储桶的多个触发器。 我创建了一个带有 s3 触发器的 lambda。第一
根据以下源代码,常规 lambda 似乎可以与扩展 lambda 互换。 fun main(args: Array) { val numbers = listOf(1, 2, 3) f
A Tutorial Introduction to the Lambda Calculus 本文介绍乘法函数 The multiplication of two numbers x and y ca
我想弄清楚如何为下面的表达式绘制语法树。首先,这究竟是如何表现的?看样子是以1和2为参数,如果n是 0,它只会返回 m . 另外,有人可以指出解析树的开始,还是一个例子?我一直找不到一个。 最佳答案
在 C++0x 中,我想知道 lambda 函数的类型是什么。具体来说: #include type1 foo(int x){ return [x](int y)->int{return x * y
我在其中一个职位发布中看到了这个问题,它询问什么是 lambda 函数以及它与高阶函数的关系。我已经知道如何使用 lambda 函数,但不太自信地解释它,所以我做了一点谷歌搜索,发现了这个:What
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
Evaluate (((lambda(x y) (lambda (x) (* x y))) 5 6) 10) in Scheme. 我不知道实际上该怎么做! ((lambda (x y) (+ x x
我正在处理 MyCustomType 的实例集合如下: fun runAll(vararg commands: MyCustomType){ commands.forEach { it.myM
Brian 在他对问题 "Are side effects a good thing?" 的论证中的前提很有趣: computers are von-Neumann machines that are
在 Common Lisp 中,如果我希望两个函数共享状态,我将按如下方式执行 let over lambda: (let ((state 1)) (defun inc-state () (in
Evaluate (((lambda(x y) (lambda (x) (* x y))) 5 6) 10) in Scheme. 我不知道实际上该怎么做! ((lambda (x y) (+ x x
作为lambda calculus wiki说: There are several possible ways to define the natural numbers in lambda cal
我有一个数据类,我需要初始化一些 List .我需要获取 JsonArray 的值(我使用的是 Gson)。 我做了这个函数: private fun arrayToList(data: JsonAr
((lambda () )) 的方案中是否有简写 例如,代替 ((lambda () (define x 1) (display x))) 我希望能够做类似的事情 (empty-lam
我在 Java library 中有以下方法: public void setColumnComparator(final int columnIndex, final Comparator colu
我正在研究一个函数来计算国际象棋游戏中棋子的有效移动。 white-pawn-move 函数有效。当我试图将其概括为任一玩家的棋子 (pawn-move) 时,我遇到了非法函数调用。我已经在 repl
考虑这段代码(在 GCC 和 MSVC 上编译): int main() { auto foo = [](auto p){ typedef decltype(p) p_t;
我正在阅读一个在 lambda 内部使用 lambda 的片段,然后我想通过创建一个虚拟函数来测试它,该函数从文件中读取然后返回最大和最小数字。 这是我想出来的 dummy = lambda path
我是一名优秀的程序员,十分优秀!