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的异常 }
关键说明
- 表达式树传递成员:调用
Check时不再直接传字段值,而是用x => x.Calls这样的表达式,让函数能解析出对应的FieldInfo(或PropertyInfo)。 - 处理值类型装箱:对于int等值类型,表达式树会自动装箱成object,需要通过
UnaryExpression拆包获取原始成员信息。 - 兼容字段和属性:通过
MemberInfo统一处理字段和属性,让函数更通用。 - 自动读取页码:从成员信息中获取
PageAttribute,拿到对应的页码后传入CheckException。
这样,当验证失败时抛出的异常就会包含错误字段所在的页码,后端返回给JavaScript后就能定位到对应的表单页面了。
内容的提问来源于stack exchange,提问作者Nikki Locke
相关产品推荐
相关产品推荐

