假设我们要为某大学写一个工资管理程序。首先是表示员工的 Employee 类(Employee.cs):
01: namespace Skyiv.Ben 02: { 03: class Employee 04: { 05: public string Department { get; private set; } 06: public string Name { get; private set; } 07: public decimal Salary { get; set; } 08: 09: public Employee(string department, string name, decimal salary) 10: { 11: Department = department; 12: Name = name; 13: Salary = salary; 14: } 15: 16: public override string ToString() 17: { 18: return string.Format("{0} {1} 工资:{2:N2}", Department, Name, Salary); 19: } 20: } 21: }
接着是表示学校中各系的 Department 类(Department.cs):
01: namespace Skyiv.Ben 02: { 03: class Department 04: { 05: public string Name { get; private set; } 06: public int Count { get; private set; } 07: public decimal TotalSalary { get; private set; } 08: 09: public Department(string name) 10: { 11: Name = name; 12: } 13: 14: public void Add(Employee employee) 15: { 16: Count++; 17: TotalSalary += employee.Salary; 18: } 19: 20: public override string ToString() 21: { 22: return string.Format("{0} 人数:{1} 总工资:{2:N2}", Name, Count, TotalSalary); 23: } 24: } 25: }
最后就是主程序 Program.cs :
01: using System; 02: using System.Collections.Generic; 03: 04: namespace Skyiv.Ben 05: { 06: class Program 07: { 08: static void Main() 09: { 10: new Program().Run(); 11: } 12: 13: void Run() 14: { 15: var employees = InitializeEmployees(); 16: SalaryRaise(employees); 17: Statistic(employees); 18: } 19: 20: List<Employee> InitializeEmployees() 21: { 22: var employees = new List<Employee>(); 23: employees.Add(new Employee("校长室", "高松年", 72767.58m)); 24: employees.Add(new Employee("政治系", "方鸿渐", 31982.45m)); 25: employees.Add(new Employee("政治系", "赵辛楣", 40126.31m)); 26: Console.WriteLine("三闾大学工资明细表:"); 27: employees.ForEach(e => Console.WriteLine(e)); 28: return employees; 29: } 30: 31: void SalaryRaise(List<Employee> employees) 32: { 33: for (var i = 0; i < employees.Count; i++) employees[i].Salary += 10000; 34: Console.WriteLine(Environment.NewLine + "加薪之后:"); 35: employees.ForEach(e => Console.WriteLine(e)); 36: } 37: 38: void Statistic(List<Employee> employees) 39: { 40: var departments = new Dictionary<string, Department>(); 41: foreach (var employee in employees) 42: { 43: var name = employee.Department; 44: Department dep; 45: if (!departments.TryGetValue(name, out dep)) departments.Add(name, dep = new Department(name)); 46: dep.Add(employee); 47: } 48: Console.WriteLine(Environment.NewLine + "三闾大学工资统计表:"); 49: foreach (var kvp in departments) Console.WriteLine(kvp.Value); 50: } 51: } 52: }
这个程序的运行结果如下所示:
如果我们把 Employee 类(class)改为结构(struct),则在编译时就会报以下错误:
这个错误发生在 Program.cs 第 33 行中的 employees[i].Salary += 10000; 语句。
我不理解这个 CS1612 错误,如果哪位朋友能够解释一下,请在评论中给出。谢谢!
如果我们把 Department 类(class)改为结构(struct):
01: namespace Skyiv.Ben 02: { 03: struct Department 04: { 05: public string Name { get; private set; } 06: public int Count { get; private set; } 07: public decimal TotalSalary { get; private set; } 08: 09: public Department(string name) : this() 10: { 11: Name = name; 12: } 13: 14: public void Add(Employee employee) 15: { 16: Count++; 17: TotalSalary += employee.Salary; 18: } 19: 20: public override string ToString() 21: { 22: return string.Format("{0} 人数:{1} 总工资:{2:N2}", Name, Count, TotalSalary); 23: } 24: } 25: }
注意上述程序中第 09 行最后要加上“ : this() ”,否则 Microsoft C# 编译器会报错(但是 Mono C# 编译器不会报错,请参见:浅谈 Microsoft C# 编译器和 Mono C# 编译器)。
再次运行该程序,运行结果的最后三行如下所示:
这是因为现在的 Department 结构是值类型,而不是引用类型。所以在 Program.cs 第 46 行的 dep.Add(employee); 语句中,dep 的值的更改不会影响到 departments 字典中的值。所以统计出来的人数和总工资都是零了。
要绕过这个陷阱很简单,在第 46 行的 dep.Add(employee); 语句后面加一句 departments[name] = dep; 就行了。
在 .NET Framework Base Class Library 中,有很多的结构(struct)。如:
- System.Int32
- System.DateTime
- System.Drawing.Size
使用时也要小心陷阱。
此外,还有注意 DateTime 的 Add 和 AddDays 等方法并不更改此 DateTime 的值。而是返回一个新的 DateTime,其值是此运算的结果。因此以下语句是不成立的:
for (var date = DateTime.MinValue; date < DateTime.Today; date.AddDays(1))
正确的应该是:
for (var date = DateTime.MinValue; date < DateTime.Today; date = date.AddDays(1))
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· [AI/GPT/综述] AI Agent的设计模式综述