码迷,mamicode.com
首页 > 编程语言 > 详细

C# 语言中 struct 的陷阱

时间:2015-07-29 10:21:41      阅读:149      评论:0      收藏:0      [点我收藏+]

标签:

假设我们要为某大学写一个工资管理程序。首先是表示员工的 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:  }

这个程序的运行结果如下所示:

三闾大学工资明细表:
校长室 高松年 工资: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.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# 编译器)。

再次运行该程序,运行结果的最后三行如下所示:

三闾大学工资统计表:
校长室 人数: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))

版权声明:本文为博主http://www.zuiniusn.com原创文章,未经博主允许不得转载。

C# 语言中 struct 的陷阱

标签:

原文地址:http://blog.csdn.net/u013948187/article/details/47121909

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!