假設我們要為某大學寫一個工資管理程式。首先是表示員工的 Employee 類(Employee.cs):
01: namespace Skyiv.Ben02: {03: class Employee04: {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.Ben02: {03: class Department04: {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.Ben05: {06: class Program07: {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: }
這個程式的運行結果如下所示:
三閭大學工資明細表:校長室 高松年 工資:72,767.58政治系 方鴻漸 工資:31,982.45政治系 趙辛楣 工資:40,126.31加薪之後:校長室 高松年 工資:82,767.58政治系 方鴻漸 工資:41,982.45政治系 趙辛楣 工資:50,126.31三閭大學工資統計表:校長室 人數:1 總工資:82,767.58政治系 人數:2 總工資:92,108.76
如果我們把 Employee 類(class)改為結構(struct),則在編譯時間就會報以下錯誤:
CS1612: 無法修改“System.Collections.Generic.List.this[int]”的傳回值,因為它不是變數。
這個錯誤發生在 Program.cs 第 33 行中的 employees[i].Salary += 10000; 語句。
我不理解這個 CS1612 錯誤,如果哪位朋友能夠解釋一下,請在評論中給出。謝謝!
如果我們把 Department 類(class)改為結構(struct):
01: namespace Skyiv.Ben02: {03: struct Department04: {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# 編譯器)。
再次運行該程式,運行結果的最後三行如下所示:
三閭大學工資統計表:校長室 人數:0 總工資:0.00政治系 人數:0 總工資:0.00
這是因為現在的 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))