C#属性Setter验证失效:构造器直接赋值为何不触发校验?
C# 属性Setter校验的常见问题与解决办法
问题描述
我需要验证用户输入的name值满足不含数字且长度在3-8字符范围内,把校验逻辑写在了Name属性的Setter里:如果不符合条件,就把私有字段设为"Unnamed"。但调用构造器直接给私有字段this.name赋值"Gigi5"时,校验没触发,返回了原值;只有构造器里改成给Name属性赋值,校验才生效。同时有两个疑问:
- 直接赋值私有字段为什么不经过Setter?
- 是否需要在Getter中加校验?
代码示例
public class Cat { private string name ="Unnamed"; private string color = "Gray"; public string Name { get { return name; // 注释掉的Getter校验逻辑 //if ((name.Length <= 8 && name.Length>=3) && Regex.IsMatch(name, @"^[a-zA-Z]$")) //{ // return name; //} //else //{ // return "Unnamed"; //} } set { if ((name.Length <= 8 && name.Length>=3) && Regex.IsMatch(name, @"^[a-zA-Z]$")) { name = value; } else { name = "Unamed"; } } } public string Color { get => color; set => color=value; } // 当前不生效的构造器 public Cat(string name, string color) { this.name = name; this.color = color; } // 注释掉的生效构造器 //public Cat(string name, string color) //{ // Name = name; // Color = color; //} }
测试代码
Cat cat1 = new Cat("Gigi5", "orange"); Console.WriteLine($"{cat1.Name}'s color is {cat1.Color}");
解答
1. 直接赋值私有字段不触发Setter的原因
私有字段是类存储数据的底层容器,属性的Setter是包裹在字段外的逻辑层——只有通过属性名赋值时,才会执行Setter里的校验逻辑;直接操作字段相当于绕过了属性的封装,自然不会触发校验。这是C#属性封装的基本特性:属性是字段的安全访问入口,字段是原始数据载体。
2. 修复构造器的校验问题
要让构造器里的赋值也触发校验,必须通过Name属性赋值,而非直接操作私有字段。修改构造器如下:
public Cat(string name, string color) { Name = name; Color = color; }
3. 修正Setter里的逻辑错误
你当前的Setter代码存在三个关键错误:
- 校验条件误用到了现有字段
name的长度,而非待赋值的value的长度,导致判断逻辑完全失效 - 正则表达式
@"^[a-zA-Z]$"只能匹配单个字母,无法匹配多字母名称,应改为@"^[a-zA-Z]+$" - 字符串拼写错误:"Unamed"应改为"Unnamed"
修正后的Setter代码:
set { // 校验value的长度在3-8之间,且全部由字母组成 if (value.Length >= 3 && value.Length <= 8 && Regex.IsMatch(value, @"^[a-zA-Z]+$")) { name = value; } else { name = "Unnamed"; } }
4. 是否需要在Getter中加校验?
不需要,原因如下:
- 私有字段
name的所有赋值入口(构造器、外部Setter)都已经经过校验,能保证存储的是合法值或默认的"Unnamed" - 在Getter中添加校验会造成逻辑冗余,甚至可能出现合法值被错误覆盖的情况
- 如果类内部存在其他直接修改私有字段的代码,优先规范内部代码、统一通过属性赋值,而非在Getter加兜底校验
测试结果
修改后运行测试代码,"Gigi5"因包含数字触发校验,cat1.Name会返回"Unnamed",输出结果为:
Unnamed's color is orange
内容的提问来源于stack exchange,提问作者Sarah Shaygani
相关产品推荐
相关产品推荐

