为什么对象会被复制多次?

Why does the object get duplicated multiple times?

我想了解对象 creation/referencing 发生的方式。我有一段代码,其中列表中的所有 Employee 对象都是重复的。顶部代码存在覆盖所有先前条目的问题,因此列表包含重复的对象,而底部是我的修复。我想了解为什么在 while.Read() 循环内创建新对象有效,而在 while 循环外创建员工对象却无效。

public IEnumerable<Employee> Employees
{
    get
    {
        List<Employee> employees = new List<Employee>();

        using (SqlConnection connection = new SqlConnection(connectionString))
        {
            Employee _employee = new Employee(); //<issue is here, all enties in employees are duplicated values of a single record
            SqlCommand sqlCmd = new SqlCommand("spGetAllEmployees", connection);
            sqlCmd.CommandType = System.Data.CommandType.StoredProcedure;
            connection.Open();
            SqlDataReader reader = sqlCmd.ExecuteReader();
            while (reader.Read())
            {
                _employee.EmployeeID = Convert.ToInt32(reader["EmployeeID"]); //object instantiation here fixed the issue, why?
                _employee.Name = (reader["Name"].ToString());
                _employee.Gender = (reader["Gender"].ToString());
                _employee.City = (reader["City"].ToString());
                _employee.DateOfBirth = Convert.ToDateTime(reader["DateOfBirth"]);
                _employee.DepartmentID = Convert.ToInt32(reader["DepartmentID"]);
                employees.Add(_employee);
            }
        }
        return employees;
    }
}

我想了解为什么这解决了这个问题。

    public IEnumerable<Employee> Employees
            {
                get
                {
                    List<Employee> employees = new List<Employee>();

                    using (SqlConnection connection = new 

SqlConnection(connectionString))
                {
                    SqlCommand sqlCmd = new SqlCommand("spGetAllEmployees", connection);
                    sqlCmd.CommandType = System.Data.CommandType.StoredProcedure;
                    connection.Open();
                    SqlDataReader reader = sqlCmd.ExecuteReader();
                    while (reader.Read())
                    {
                        Employee _employee = new Employee(); //this fixed the issue, why?
                        _employee.EmployeeID = Convert.ToInt32(reader["EmployeeID"]);
                        _employee.Name = (reader["Name"].ToString());
                        _employee.Gender = (reader["Gender"].ToString());
                        _employee.City = (reader["City"].ToString());
                        _employee.DateOfBirth = Convert.ToDateTime(reader["DateOfBirth"]);
                        _employee.DepartmentID = Convert.ToInt32(reader["DepartmentID"]);
                        employees.Add(_employee);
                    }
                    }
                    return employees;
                }
            }

在您的第一个示例中,您有一个在循环外创建的 _employee 对象。该对象存储在内存中的单个引用中。当您使用 Add(_employee) 时,您并不是使用 _employee 的当前属性创建新对象,而是多次将对内存中单个对象的引用添加到列表中。当您在循环的后续行程中更改 _employee 的任何属性的值时,您正在更改内存中的单个对象,这实际上是更改列表中的每个项目。

在第二个示例中,您在 while 的每个循环中创建一个新的 _employee 对象,并且每个新对象都有一个新的内存地址。因此,您添加到列表中的每个对象都独立于最后一个。

Typeof Employee 是一个引用类型,它只是指向保存真实数据的另一个内存位置的指针。

在第一个示例中,您只初始化了 Employee 的一个实例(引用类型)。在 while 循环中,您不断将同一个实例添加到集合中,同时更新其属性(集合中的所有项目都将其属性设置为数据库中最后一行的值)。

在第二个示例中,您在每次迭代中创建一个新实例并根据当前行设置其属性。下一次迭代创建另一个实例并设置其属性。

This article 可能有助于解释引用类型和值类型之间的区别。