You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Blazor表单中如何实现任意类型属性的IsRequired()直接调用?

问题场景

现有如下DTO类,需要在Blazor表单中根据Required特性为字段显示必填星号:

public class MyDto
{
    [Required]
    public string MyProperty1 { get; set; }
}

当前使用的扩展方法需要手动传入属性名,调用繁琐:

public static bool IsRequired(this object obj, string propertyName)
{
    var objectType = obj.GetType();
    var property = objectType.GetProperty(propertyName);
    if (property == null)
    {
        throw new ArgumentException($"Property '{propertyName}' not found on type '{objectType.Name}'");
    }

    return property.GetCustomAttributes(true).OfType<RequiredAttribute>().Any();
}

调用示例:

_myDto.IsRequired(nameof(MyDto.MyProperty1))

希望实现更简便的调用方式,比如直接通过属性实例调用:_myDto.MyProperty1.IsRequired(),且方法需支持string、int、枚举等任意类型属性。

解决方案

推荐方案:表达式树扩展方法

通过表达式树实现编译时类型安全的调用,无需手动编写nameof,同时简化调用语法:

using System.Linq.Expressions;
using System.ComponentModel.DataAnnotations;

public static class RequiredExtensions
{
    public static bool IsRequired<T, TProp>(this T obj, Expression<Func<T, TProp>> propertyExpression)
    {
        if (propertyExpression.Body is not MemberExpression memberExpr || memberExpr.Member is not System.Reflection.PropertyInfo property)
        {
            throw new ArgumentException("表达式必须指向属性访问器", nameof(propertyExpression));
        }

        return property.GetCustomAttributes(true).OfType<RequiredAttribute>().Any();
    }
}

调用示例:

// 编译时自动检查属性名,无需手动输入字符串
_myDto.IsRequired(x => x.MyProperty1);

该方案优势:

  • 编译时验证属性名,避免拼写错误
  • 语法简洁,比原nameof方式更直观
  • 支持任意类型的属性,无需针对不同类型单独实现

属性实例直接调用的局限性说明

如果一定要实现_myDto.MyProperty1.IsRequired()的形式,存在本质限制:属性值本身无法关联回所属的对象和对应的属性元数据。比如当属性是值类型(如int)时,调用扩展方法的是值的副本,无法追溯到原DTO的属性信息。若强行实现,需要额外传递对象上下文,反而会增加复杂度,因此不推荐这种形式。

Blazor原生场景优化

如果是在Blazor的EditForm中使用,还可以结合EditContext和FieldIdentifier直接获取字段的验证特性,无需额外扩展方法:

<EditForm Model="@_myDto" EditContext="@_editContext">
    <div class="form-group">
        <label>
            My Property 1
            @if (IsRequiredField(nameof(MyDto.MyProperty1)))
            {
                <span class="text-danger ms-1">*</span>
            }
        </label>
        <InputText @bind-Value="_myDto.MyProperty1" />
    </div>
</EditForm>

@code {
    private MyDto _myDto = new();
    private EditContext _editContext;

    protected override void OnInitialized()
    {
        _editContext = new EditContext(_myDto);
    }

    private bool IsRequiredField(string fieldName)
    {
        var fieldId = new FieldIdentifier(_myDto, fieldName);
        var property = _myDto.GetType().GetProperty(fieldName);
        return property?.GetCustomAttributes(true).OfType<RequiredAttribute>().Any() ?? false;
    }
}

内容的提问来源于stack exchange,提问作者Patrick

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 16:34:58