C# 語言中 struct 的陷阱

來源:互聯網
上載者:User

假設我們要為某大學寫一個工資管理程式。首先是表示員工的 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))
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.