C#泛型方法无法编译,如何实现通用字段重复校验?
如何实现校验字段重复的泛型方法?
现有集合与非泛型校验方法:
public IEnumerable<UserRole> SystemUserRoles { get; set; } public IEnumerable<User> Users { get; set; } private bool CheckUserRoleNameForDoubling(UserRole userRole) { var userRoles = SystemUserRoles.ToList(); userRoles.Remove(userRole); return !userRoles.Select(p => p.Name).Contains(userRole.Name); } private bool CheckLoginForDoubling(User user) { var userList = Users.ToList(); userList.Remove(user); return !userList.Select(p => p.Login).Contains(user.Login); }
尝试编写泛型方法但编译失败:
private bool CheckFieldForDoubling<T>(T obj, IEnumerable<T> col, string field) { var list = col.ToList(); list.Remove(obj); return !list.Select(p => ((T)p)[field]).Contains(obj[field]); }
报错信息:无法对类型为'T'的表达式应用索引器[]
UPDATE1:这些方法用于在集合对象添加/编辑后、存入数据库前做重复校验。
方案1:使用委托(推荐,类型安全且高效)
放弃字符串传字段名的方式,改用Func<T, object>委托传入字段选择逻辑,既保证类型安全,又避免反射带来的性能损耗:
private bool CheckFieldForDoubling<T>(T obj, IEnumerable<T> col, Func<T, object> fieldSelector) { var list = col.ToList(); list.Remove(obj); var targetValue = fieldSelector(obj); return !list.Select(fieldSelector).Contains(targetValue); }
调用示例:
// 校验UserRole的Name字段 CheckFieldForDoubling(role, SystemUserRoles, r => r.Name); // 校验User的Login字段 CheckFieldForDoubling(user, Users, u => u.Login);
方案2:使用反射(适配字符串字段名场景)
如果必须通过字符串指定字段名,可通过反射获取属性/字段的值来实现:
using System.Reflection; private bool CheckFieldForDoubling<T>(T obj, IEnumerable<T> col, string fieldName) { var list = col.ToList(); list.Remove(obj); // 优先获取属性(如果是字段则替换为GetField) PropertyInfo prop = typeof(T).GetProperty(fieldName); if (prop == null) throw new ArgumentException($"类型{typeof(T)}中不存在名为{fieldName}的属性"); var targetValue = prop.GetValue(obj); return !list.Any(item => Equals(prop.GetValue(item), targetValue)); }
调用示例:
// 用nameof避免硬编码字符串出错 CheckFieldForDoubling(role, SystemUserRoles, nameof(UserRole.Name)); CheckFieldForDoubling(user, Users, nameof(User.Login));
内容的提问来源于stack exchange,提问作者Eugene
相关产品推荐
相关产品推荐

