Blazor-Server中如何通过动态Linq创建合法的ValueExpression
Blazor通用输入组件ValueExpression构建异常解决方案
错误原因
你的表达式构建逻辑存在宿主对象类型不匹配的问题:
- 第一种写法:
Expression.Constant(Value, typeof(TValue))生成的是TValue类型的实例常量,你试图从这个TValue实例上获取FormField<TValue>类的Value属性,而DateTime等实际传入的TValue类型本身没有名为Value的属性,因此抛出异常。 - 第二种写法:声明的表达式参数是
TValue类型,同样试图从该类型实例上获取不存在的Value属性,也会触发同类错误。
解决方案
方案一:框架自动传入表达式(推荐)
符合Blazor双向绑定规范,同时原生支持EditForm表单验证:
- 为
FormField<TValue>新增ValueExpression参数,框架在使用@bind-语法时会自动传入对应表达式:
[Parameter] public Expression<Func<TValue>> ValueExpression { get; set; }
- 修改
BuildInput方法,直接使用该参数赋值给内置输入组件,不需要手动构建表达式:
private RenderFragment BuildInput() { return builder => { builder.OpenComponent(0, GetInputType()); builder.AddAttribute(1, "Value", Value); builder.AddAttribute(2, "ValueChanged", ValueChanged); builder.AddAttribute(3, "ValueExpression", ValueExpression); builder.AddAttribute(4, "id", Id); builder.AddAttribute(5, "class", "input"); builder.CloseComponent(); }; }
- 父组件使用时直接用
@bind-Value语法即可:
<FormField TValue="DateTime" Id="birth" Label="出生日期" @bind-Value="User.Birthday" />
方案二:手动构建合法表达式
如果你确实需要自行生成表达式,需要将表达式宿主改为当前FormField<TValue>实例:
private RenderFragment BuildInput() { // 构建表达式:() => this.Value var thisInstance = Expression.Constant(this, typeof(FormField<TValue>)); var valueProperty = typeof(FormField<TValue>).GetProperty(nameof(Value)); var propertyAccess = Expression.Property(thisInstance, valueProperty); var valueExpression = Expression.Lambda<Func<TValue>>(propertyAccess); return builder => { builder.OpenComponent(0, GetInputType()); builder.AddAttribute(1, "Value", Value); builder.AddAttribute(2, "ValueChanged", ValueChanged); builder.AddAttribute(3, "ValueExpression", valueExpression); builder.AddAttribute(4, "id", Id); builder.AddAttribute(5, "class", "input"); builder.CloseComponent(); }; }
注意:该方案生成的表达式仅指向当前组件的Value属性,无法识别父组件绑定的模型字段,表单验证的字段名提示和特性识别会失效,仅适合不需要表单验证的场景。
内容的提问来源于stack exchange,提问作者GrayFox
相关产品推荐
相关产品推荐

