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

C#构造函数初始化最佳实践:交互逻辑应内置于构造函数吗?

类初始化与构造函数的最佳实践咨询

我正在学习C#的类相关知识,现咨询类初始化与构造函数的最佳实践问题。在完成《Player's Guide C#》的练习时,我编写了如下Arrows类代码:

internal class Arrows
{
    /// <summary>
    /// Basic Practice class to ask for and define details of an arrow
    /// </summary>
    private enum _arrowhead
    {
        // Type of arrowhead
        Steel,
        Wood,
        Obsidian,
    }

    private enum _fletching
    {
        // Type of fletching
        Plastic,
        TurkeyFeathers,
        GooseFeathers,
    }
    
    private int _shaftLength = 60;   // default length of arrows is 60cm
    private float _shaftCostPerCm = 0.05f;
    private float _costOfArrow;

    public Arrows() {
        Console.WriteLine("Hello dear customer");
        Console.WriteLine("Welcome to my arrow shop\n");
        Console.WriteLine("First things first, what type of arrowhead would you like");
        foreach (string head in Enum.GetNames(typeof(_arrowhead)))
        {
            Console.WriteLine(head + " = " + getHeadPrices(head) + " gold");
        }
        string _Head = Console.ReadLine();

        Console.WriteLine("\nTime now to select the type of fletching");
        foreach (string fletch in Enum.GetNames(typeof(_fletching)))
        {
            Console.WriteLine(fletch + " = " + getFletchingPrices(fletch) + " gold");
        }
        string _fletchingType = Console.ReadLine();

        Console.WriteLine("\nHow long do you want the arrows to be?");
        Console.WriteLine("I can manage to make arrows between 60 and 100 cm");
        _shaftLength = Convert.ToInt32(Console.ReadLine());

        _costOfArrow = singleArrowCost(_Head, _fletchingType, _shaftLength, _shaftCostPerCm);
        Console.WriteLine($"\nThe cost of one of these arrows is {_costOfArrow}");
    }
}

当前我的构造函数中包含大量控制台用户交互逻辑,想咨询:将这些用户交互逻辑放在类外部收集参数后传入构造函数,与直接在构造函数内处理相比,哪种方式更符合C#的最佳实践?


将用户交互逻辑放在类外部收集参数后传入构造函数,是更符合C#最佳实践的做法,核心原因如下:

  • 单一职责原则:Arrows类的核心职责应该是封装箭的属性、计算成本这类和箭本身强相关的逻辑,控制台交互属于输入收集的UI职责,两者完全分离才能让类的职责更清晰,后续维护和修改也更简单。
  • 可测试性提升:如果构造函数里硬写了控制台输入,你无法针对成本计算逻辑写自动化单元测试——总不能每次测试都手动输入参数。把参数传入构造函数后,你可以直接传入各种测试用例,快速验证逻辑是否正确。
  • 扩展性更强:如果以后需要换输入方式(比如从配置文件读参数、或者用GUI界面收集),不需要修改Arrows类的任何代码,只要调整外部的参数收集逻辑即可,符合开闭原则。
  • 回归构造函数本质:构造函数的核心作用是初始化对象状态,让对象从创建开始就处于合法可用的状态,而不是处理复杂的用户交互流程。把交互逻辑抽出去,构造函数只负责接收必要参数并完成初始化,代码逻辑会更简洁。

另外针对你的代码还有几个小建议:

  • 按照C#命名规范,枚举应该采用PascalCase命名,比如Arrowhead、Fletching,去掉下划线前缀。
  • 可以把箭头类型、箭羽类型、箭杆长度这些核心属性设为类的成员变量,让Arrows对象能完整表示一支箭的所有信息。
  • 建议编写带参数的构造函数,比如public Arrows(Arrowhead headType, Fletching fletchingType, int shaftLength),确保对象初始化时就传入合法参数,避免状态异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 06:34:54