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

C#开发中是否应将所有Getter/Setter属性类型设为string?

你的写法确实是不良实践,但问题不在「把校验放在setter里」

你觉得把校验逻辑收敛在属性setter里更整洁的直觉是对的——属性setter中放合法性校验本身是非常标准的最佳实践,真正的问题是你为了接住控制台的字符串输入,强行把本应为数值类型的GPA属性定义成了string,属于典型的类型设计和职责划分错位。

这种写法的核心问题

  • 首先是类型语义完全错配
    GPA的本质是0-10区间的浮点数,不是字符串。把对外暴露的GPA属性设为string会带来大量无意义的额外成本:后续要做平均分计算、成绩排序、及格统计这类操作时,每次都要先把字符串转成double,还要反复处理转换失败的异常;同一个GPA值可能对应多种字符串写法(比如4.5、4.50、4.5 (末尾带空格)),后续做值比较的时候很容易出现逻辑bug。
  • 其次是职责边界混乱
    你把两类完全不同的校验逻辑揉在了一起:
    • 属于Student类本身的领域规则校验:比如姓名不能含数字、不能为空,GPA必须在0-10区间——这类校验放在setter里是完全正确的,不管数据来自控制台、接口请求还是数据库,只要给Student属性赋值就会自动校验,从根源上避免非法对象被创建。
    • 属于交互层的输入格式校验:比如用户在控制台敲的一串字符能不能转成合法的double——这部分是主程序(输入/UI层)的职责,根本不该塞到Student类里。Student类不需要关心数据是从哪来的,它只需要接收符合自己类型定义的合法值即可。
  • 顺便提一句,你现在写的姓名校验逻辑还有bug:现有判断条件会允许全空格的姓名通过校验,且逻辑运算符的组合很容易出边界错误。

推荐的改法

把GPA属性改回double类型,setter里只保留数值范围的合法性校验,输入格式转换的逻辑移到主程序中处理即可。

修正后的Student类代码:

public class Student
{
    private string name;
    private double gpa;

    internal string Name
    {
        get { return name; }
        set
        {
            if (!string.IsNullOrWhiteSpace(value) && value.All(c => !char.IsDigit(c)))
            {
                name = value;
            }
            else
            {
                throw new ArgumentException("Student's name is not valid");
            }
        }
    }

    internal double GPA
    {
        get { return gpa; }
        set
        {
            if (value >= 0 && value <= 10)
            {
                gpa = value;
            }
            else
            {
                throw new ArgumentOutOfRangeException("Student's GPA must be between 0 and 10");
            }
        }
    }

    public override string ToString()
    {
        return $"Student's name: {Name}\nStudent's GPA: {GPA}";
    }
}

调整后的主程序逻辑:

Student student = new Student();
while (true)
{
    try
    {
        Console.WriteLine("Enter student's name: ");
        string nameInput = Console.ReadLine();
        student.Name = nameInput;

        Console.WriteLine("Enter student's GPA: ");
        string gpaInput = Console.ReadLine();
        // 输入层先处理格式转换校验,转换成功后再赋值给领域对象
        if (!double.TryParse(gpaInput, out double gpaValue))
        {
            Console.WriteLine("GPA input is not a valid number, please try again");
            continue;
        }
        student.GPA = gpaValue;

        Console.WriteLine(student.ToString());
        break;
    }
    catch (Exception e)
    {
        Console.WriteLine(e.Message);
    }
}

这种写法的好处很明显:Student类完全不依赖控制台交互逻辑,后续你要做桌面端、Web端功能的时候,这个类可以直接复用;所有数值操作可以直接调用GPA属性,不需要反复做类型转换;错误边界也更清晰:输入格式错误由交互层提示,数值非法由对象校验拦截,不会把两类不同的错误混为一谈。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 09:45:32