为什么我的列表中的成员被该列表的最后一个成员覆盖



我正在尝试编写一个程序,打印出(在字符串变量中)关于mdb数据库的以下信息:

表名表的总列数

列列表如下:

栏目名称:列数据类型:

为了完成这个任务,我使用了两个自定义类型(公共类),当然还有列表。以下是我到目前为止的代码(顺便说一下,由于这里收集的问题和答案,这些代码在很大程度上进行了调整):

下面是我创建的用来定义我正在使用的两种新类型的类:

public class ClmnInfo
{
    public string strColumnName { get; set; }
    public string strColumnType { get; set; }
}
public class TblInfo
{
    public string strTableName { get; set; }
    public int intColumnsQty { get; set; }
    public List<ClmnInfo> ColumnList { get; set; }
}

下面是实际获取数据的代码。请记住,我使用OleDB连接到实际数据,一切都很好,除了我将在下面描述的问题。作为一个示例,我目前正在用一个简单的1表db测试此代码,包含12列类型的字符串保存为1 int32(访问中的长Int)。

//Here I declare and Initialize all relevant variables and Lists
TblInfo CurrentTableInfo = new TblInfo();
ClmnInfo CurrentColumnInfo = new ClmnInfo();
List<TblInfo> AllTablesInfo = new List<TblInfo>();
 //This loop iterates through each table obtained and imported previously in the program
int i = 0;
foreach (DataTable dt in dtImportedTables.Tables)
{

    CurrentTableInfo.strTableName = Globals.tblSchemaTable.Rows[i][2].ToString(); //Gets the name of the current table
    CurrentTableInfo.intColumnsQty = dt.Columns.Count; //Gets the total number of columns in the current table
    CurrentTableInfo.ColumnList = new List<ClmnInfo>(); //Initializes the list which will house all of the columns 
    //This loop iterates through each column in the current table
    foreach (DataColumn dc in dt.Columns)
    {
        CurrentColumnInfo.ColumnName = dc.ColumnName;  // Gets the current column name
        CurrentColumnInfo.ColumnType = dc.DataType.Name; // Gets the current column data type
        CurrentTableInfo.ColumnList.Add(CurrentColumnInfo); // adds the information just obtained as a member of the columns list contained in CurrentColumnInfo 
     }
//BAD INSTRUCTION FOLLOWS:
        AllTablesInfo.Add(CurrentTableInfo); //This SHOULD add The collection of column_names and column_types in a "master" list containing the table name, the number of columns, and the list of columns
    }

我调试了代码并观察了所有变量。它工作得很好(表名和列数量得到了正确的注册,以及表的column_names和column_types列表),但是当执行"坏"指令时,AllTablesInfo的内容完全不是它们应该有的样子。表名是正确的,列的数量也是正确的,列列表甚至有12个成员,但列表的每个成员都是相同的,即我正在检查的数据库的LAST列。有人能向我解释为什么CurrentTableInfo以这种方式被覆盖,当它被添加到AllTablesInfo列表?

您正在创建一个单个 TblInfo对象,然后在每次迭代中更改属性。您的列表包含对同一对象的大量引用。只需移动这一行:

TblInfo CurrentTableInfo = new TblInfo();

到第一个循环里面的,这一行:

ClmnInfo CurrentColumnInfo = new ClmnInfo();

在嵌套的foreach循环中,以便在每次迭代中创建新的实例。下:

    重要

  • 确保您理解为什么之前会失败。如果你不确定c#中对象和引用(以及值类型)是如何工作的,请阅读我关于引用的文章
  • 为局部变量使用camelCased名称而不是CamelCased名称
  • 考虑为ClmnInfo使用对象初始化器
  • 更改类型名称以避免不必要的缩写(TableInfo, ColumnInfo)
  • 更改属性名以避免伪匈牙利符号,并将其更改为PascalCased
  • 考虑将整个东西重写为LINQ查询(相对高级)

linq之前的修改会让你的代码看起来像这样:

List<TableInfo> tables = new List<TableInfo>();
int i = 0;
foreach (DataTable dt in dtImportedTables.Tables)
{
    TableInfo table = new TableInfo
    {
        Name = Globals.tblSchemaTable.Rows[i][2].ToString(),
        // Do you really need this? Won't it be the same as Columns.Count?
        ColumnCount = dt.Columns.Count,
        Columns = new List<ColumnInfo>()
    };
    foreach (DataColumn dc in dt.Columns)
    {
        table.Columns.Add(new ColumnInfo {
                            Name = dc.ColumnName,
                            Type = dc.DataType.Name
                          });
    }
    tables.Add(table); 
    // I assume you meant to include this?
    i++;
}
用LINQ

:

List<TableInfo> tables = 
    dtImportedTables.Tables.Zip(Globals.tblSchemaTable.Rows.AsEnumerable(),
        (table, schemaRow) => new TableInfo {
            Name = schemaRow[2].ToString(),
            // Again, only if you really need it
            ColumnCount = table.Columns.Count,
            Columns = table.Columns.Select(column => new ColumnInfo {
                        Name = column.ColumnName,
                        Type = column.DataType.Name
                      }).ToList()
        }
    }).ToList();

您只创建了一个TblInfo实例。

这是因为您只有一个TblInfo实例,您要在循环中不断更新它,然后向List添加另一个对它的引用。因此,你的列表在内存中有许多对同一个对象的引用。

将CurrentTableInfo实例的创建移到for循环中

最新更新