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

C#中如何获取传入函数的变量所属父对象?多页表单验证场景

自动获取验证字段所属的Page特性页码

我用C#和JavaScript实现了一套通用表单填充系统,表单数据来自C#类。现在要升级支持多页表单(无需回调后端切换页面),给类成员加了PageAttribute标记字段所属页码。

表单提交到后端后会用C#函数验证输入,无效则返回错误信息。当前用Check函数执行验证,断言失败时抛出异常,但需要让异常包含错误字段所在的页码——也就是传入字段值后,自动确定它所属的类成员,查询对应的页码并返回。

原代码里的Check函数没法自动关联传入的item到类的成员,下面是解决方法:

核心思路

直接传字段值无法反向获取成员元数据,改用表达式树传递成员访问逻辑,这样就能从表达式中提取成员信息,进而读取PageAttribute的页码。

修改后的代码实现

完整代码示例

public class PageAttribute : Attribute
{
    public int Page;
    public PageAttribute(int page)
    {
        Page = page;
    }
}

public class Example
{
    public int Id;
    [Page(1)]
    public string Name;
    [Page(1)]
    public string Address;
    [Page(2)]
    public int Calls;
    [Page(2)]
    public int Emails;
}

public class CheckException : ApplicationException
{
    public int Page;
    public CheckException(string message, int page = 0) : base(message)
    {
        Page = page;
    }
}

// 修改后的Check函数,支持字段和属性
void Check<T, TMember>(T obj, Expression<Func<T, TMember>> memberExpression, Func<TMember, bool> validate, string message)
{
    MemberInfo memberInfo;
    // 处理值类型装箱的情况(比如int转object)
    if (memberExpression.Body is UnaryExpression unaryExpr)
    {
        memberInfo = ((MemberExpression)unaryExpr.Operand).Member;
    }
    else if (memberExpression.Body is MemberExpression memberExpr)
    {
        memberInfo = memberExpr.Member;
    }
    else
    {
        throw new ArgumentException("仅支持字段或属性的访问表达式");
    }

    // 获取成员值
    object memberValue = memberInfo switch
    {
        FieldInfo field => field.GetValue(obj),
        PropertyInfo property => property.GetValue(obj),
        _ => throw new ArgumentException("不支持的成员类型")
    };

    // 执行验证
    if (!validate((TMember)memberValue))
    {
        // 获取Page特性的页码
        PageAttribute pageAttr = memberInfo.GetCustomAttribute<PageAttribute>();
        int page = pageAttr?.Page ?? 0;
        throw new CheckException(message, page);
    }
}

void Main()
{
    Example e = new Example() { Id = 1, Name = "test", Calls = 3 };
    // 调用方式改为传递成员访问表达式
    Check(e, x => x.Calls, x => x == 3, "Calls not equal to 3");
    Check(e, x => x.Calls, x => x == 2, "Calls not equal to 2"); // 抛出带页码2的异常
}

关键说明

  1. 表达式树传递成员:调用Check时不再直接传字段值,而是用x => x.Calls这样的表达式,让函数能解析出对应的FieldInfo(或PropertyInfo)。
  2. 处理值类型装箱:对于int等值类型,表达式树会自动装箱成object,需要通过UnaryExpression拆包获取原始成员信息。
  3. 兼容字段和属性:通过MemberInfo统一处理字段和属性,让函数更通用。
  4. 自动读取页码:从成员信息中获取PageAttribute,拿到对应的页码后传入CheckException。

这样,当验证失败时抛出的异常就会包含错误字段所在的页码,后端返回给JavaScript后就能定位到对应的表单页面了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 04:57:42