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

C#属性Setter验证失效:构造器直接赋值为何不触发校验?

C# 属性Setter校验的常见问题与解决办法

问题描述

我需要验证用户输入的name值满足不含数字且长度在3-8字符范围内,把校验逻辑写在了Name属性的Setter里:如果不符合条件,就把私有字段设为"Unnamed"。但调用构造器直接给私有字段this.name赋值"Gigi5"时,校验没触发,返回了原值;只有构造器里改成给Name属性赋值,校验才生效。同时有两个疑问:

  1. 直接赋值私有字段为什么不经过Setter?
  2. 是否需要在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 06:43:12