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

C#中如何向自定义验证器传递字段或动态变化的值

问题描述

初始定义的File类代码如下:

public class File {
    [Required, MinLength(1, ErrorMessage = "The Header should contain at least one element")]    
    public List<string> Header { get; set; }
    [ColumnLenghts]
    public List<int> ColumnLenghts { get; set; }
    //other fields
}

需要在自定义的ColumnLenghts验证器中实现校验逻辑:判断ColumnLenghts的元素数量与Header的元素数量一致,验证器初始代码如下:

public class ColumnLenghtsAttribute : ValidationAttribute
{
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        List<int> columnLengths = (List<int>) value;
        // other checks
        if(columnLengths.Count != Header.Count) {
            return new ValidationResult(" number of column length does not match to headers");
        }
        return ValidationResult.Success;
    }
}

尝试通过给特性传headerCount = Header.Count的方式获取Header长度时,编译报错:an object reference is required for the non-static field,需要确认如何在自定义验证器中获取类实例的动态字段/属性值。

报错原因

C#中特性的参数属于编译期常量,在代码编译阶段就会被解析固化,而类的实例字段/属性是运行时创建对象后才会生成具体值,编译阶段不存在实例对象,自然无法直接引用非静态的Header.Count给特性属性赋值,这就是报错的根本原因。

实现方案

不需要在特性标注时传递动态值,自定义验证方法入参里的ValidationContext对象已经携带了当前被校验的类实例信息,直接通过它就能访问同实例下的其他属性,这是实现跨属性校验的标准方式。

针对当前场景的简单实现

直接在验证逻辑中获取当前File实例,访问Header属性做对比即可:

public class ColumnLenghtsAttribute : ValidationAttribute
{
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        // 获取当前被校验的File类实例
        var file = validationContext.ObjectInstance as File;
        if (file == null)
        {
            return new ValidationResult("校验目标类型错误");
        }

        List<int> columnLengths = value as List<int>;
        // 空值场景交给Required等独立校验特性处理,此处直接放行
        if (columnLengths == null || file.Header == null)
        {
            return ValidationResult.Success;
        }

        if(columnLengths.Count != file.Header.Count) {
            return new ValidationResult("列长度配置的数量与表头列数不匹配");
        }
        return ValidationResult.Success;
    }
}

使用时不需要给ColumnLenghts特性传任何额外参数,直接标注在属性上即可正常运行。

通用可复用实现

如果需要让这个验证特性不与File类强绑定,可以通过传入对比属性名、反射取值的方式做通用实现:

public class ColumnLenghtsAttribute : ValidationAttribute
{
    /// <summary>
    /// 要对比元素数量的属性名
    /// </summary>
    public string CompareProperty { get; set; }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        if (string.IsNullOrWhiteSpace(CompareProperty))
        {
            return new ValidationResult("未指定需要对比的属性");
        }

        // 从当前校验实例中反射获取目标属性
        var targetPropertyInfo = validationContext.ObjectType.GetProperty(CompareProperty);
        if (targetPropertyInfo == null)
        {
            return new ValidationResult($"未找到名为{CompareProperty}的属性");
        }

        var targetValue = targetPropertyInfo.GetValue(validationContext.ObjectInstance) as IList;
        if (value is not IList currentList || targetValue == null)
        {
            // 空值场景交给其他校验特性处理
            return ValidationResult.Success;
        }

        if (currentList.Count != targetValue.Count)
        {
            return new ValidationResult("当前集合元素数量与对比属性的集合元素数量不匹配");
        }

        return ValidationResult.Success;
    }
}

使用时只需要传入要对比的属性名即可,支持任意类型的集合长度对比:

public class File {
    [Required, MinLength(1, ErrorMessage = "The Header should contain at least one element")]    
    public List<string> Header { get; set; }
    [ColumnLenghts(CompareProperty = nameof(Header))]
    public List<int> ColumnLenghts { get; set; }
    //other fields
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 16:34:46