3

DataTable.Rows.Add() 向数据表中添加一行。但是,它如何处理底层数组?

一次添加一行时,是否会在添加每一行的情况下重建整个数组?

或者它是否能够简单地修改现有阵列而不会影响性能?

我想知道在用数据填充数组之前确定数组的大小是否更好,或者数据表是否能够以某种方式修改集合而无需(在幕后)复制和移动内容。

我的理解是,要调整数组,您必须重新定义它并将以前存在的数据移动到新结构中。

我的问题是 Collection.Add() 方法的工作流程是什么?

4

1 回答 1

3

使用DotPeek 之类的软件看一下:

DataTable.Rows.Add(DataRow row)
{
    this.table.AddRow(row, -1);
}

调用:

DataTable.AddRow(DataRow row, int proposedID)
{
    this.InsertRow(row, proposedID, -1);
}

调用:

DataTable.InsertRow(DataRow row, int proposedID, int pos)
{
    this.InsertRow(row, (long) proposedID, pos, true);
}  

调用:

DataTable.InsertRow(DataRow row, long proposedID, int pos, bool fireEvent)
{
    Exception deferredException = (Exception) null;
    if (row == null)
        throw ExceptionBuilder.ArgumentNull("row");
    if (row.Table != this)
        throw ExceptionBuilder.RowAlreadyInOtherCollection();
    if (row.rowID != -1L)
        throw ExceptionBuilder.RowAlreadyInTheCollection();
    row.BeginEdit();
    int proposedRecord = row.tempRecord;
    row.tempRecord = -1;
    if (proposedID == -1L)
        proposedID = this.nextRowID;
    bool flag;
    if (flag = this.nextRowID <= proposedID)
        this.nextRowID = checked (proposedID + 1L);
    try
    {
        try
        {
            row.rowID = proposedID;
            this.SetNewRecordWorker(row, proposedRecord, DataRowAction.Add, false, false, pos, fireEvent, out deferredException);
        }
        catch
        {
            if (flag && this.nextRowID == proposedID + 1L)
                this.nextRowID = proposedID;
            row.rowID = -1L;
            row.tempRecord = proposedRecord;
            throw;
        }
        if (deferredException != null)
            throw deferredException;
        if (!this.EnforceConstraints || this.inLoad)
            return;
        int count = this.columnCollection.Count;
        for (int index = 0; index < count; ++index)
        {
            DataColumn dataColumn = this.columnCollection[index];
            if (dataColumn.Computed)
                dataColumn.CheckColumnConstraint(row, DataRowAction.Add);
        }
    }
    finally
    {
        row.ResetLastChangedColumn();
    }
}

调用:

DataTable.SetNewRecordWorker(DataRow row, int proposedRecord, DataRowAction action, bool isInMerge, bool suppressEnsurePropertyChanged, int position, bool fireEvent, out Exception deferredException)
{
    deferredException = (Exception) null;
    if (row.tempRecord != proposedRecord)
    {
    if (!this.inDataLoad)
    {
        row.CheckInTable();
        this.CheckNotModifying(row);
    }
    if (proposedRecord == row.newRecord)
    {
        if (!isInMerge)
        return;
        this.RaiseRowChanged((DataRowChangeEventArgs) null, row, action);
        return;
    }
    else
        row.tempRecord = proposedRecord;
    }
    DataRowChangeEventArgs args = (DataRowChangeEventArgs) null;
    try
    {
    row._action = action;
    args = this.RaiseRowChanging((DataRowChangeEventArgs) null, row, action, fireEvent);
    }
    catch
    {
    row.tempRecord = -1;
    throw;
    }
    finally
    {
    row._action = DataRowAction.Nothing;
    }
    row.tempRecord = -1;
    int record = row.newRecord;
    int num = proposedRecord != -1 ? proposedRecord : (row.RowState != DataRowState.Unchanged ? row.oldRecord : -1);
    if (action == DataRowAction.Add)
    {
    if (position == -1)
        this.Rows.ArrayAdd(row);
    else
        this.Rows.ArrayInsert(row, position);
    }
    List<DataRow> cachedRows = (List<DataRow>) null;
    if ((action == DataRowAction.Delete || action == DataRowAction.Change) && (this.dependentColumns != null && this.dependentColumns.Count > 0))
    {
    cachedRows = new List<DataRow>();
    for (int index = 0; index < this.ParentRelations.Count; ++index)
    {
        DataRelation relation = this.ParentRelations[index];
        if (relation.ChildTable == row.Table)
        cachedRows.InsertRange(cachedRows.Count, (IEnumerable<DataRow>) row.GetParentRows(relation));
    }
    for (int index = 0; index < this.ChildRelations.Count; ++index)
    {
        DataRelation relation = this.ChildRelations[index];
        if (relation.ParentTable == row.Table)
        cachedRows.InsertRange(cachedRows.Count, (IEnumerable<DataRow>) row.GetChildRows(relation));
    }
    }
    if (!suppressEnsurePropertyChanged && !row.HasPropertyChanged && (row.newRecord != proposedRecord && -1 != proposedRecord) && -1 != row.newRecord)
    {
    row.LastChangedColumn = (DataColumn) null;
    row.LastChangedColumn = (DataColumn) null;
    }
    if (this.LiveIndexes.Count != 0)
    {
    if (-1 == record && -1 != proposedRecord && (-1 != row.oldRecord && proposedRecord != row.oldRecord))
        record = row.oldRecord;
    DataViewRowState recordState1 = row.GetRecordState(record);
    DataViewRowState recordState2 = row.GetRecordState(num);
    row.newRecord = proposedRecord;
    if (proposedRecord != -1)
        this.recordManager[proposedRecord] = row;
    DataViewRowState recordState3 = row.GetRecordState(record);
    DataViewRowState recordState4 = row.GetRecordState(num);
    this.RecordStateChanged(record, recordState1, recordState3, num, recordState2, recordState4);
    }
    else
    {
    row.newRecord = proposedRecord;
    if (proposedRecord != -1)
        this.recordManager[proposedRecord] = row;
    }
    row.ResetLastChangedColumn();
    if (-1 != record && record != row.oldRecord && (record != row.tempRecord && record != row.newRecord) && row == this.recordManager[record])
    this.FreeRecord(ref record);
    if (row.RowState == DataRowState.Detached && row.rowID != -1L)
    this.RemoveRow(row, false);
    if (this.dependentColumns != null)
    {
    if (this.dependentColumns.Count > 0)
    {
        try
        {
        this.EvaluateExpressions(row, action, cachedRows);
        }
        catch (Exception ex)
        {
        if (action != DataRowAction.Add)
            throw ex;
        deferredException = ex;
        }
    }
    }
    try
    {
    if (!fireEvent)
        return;
    this.RaiseRowChanged(args, row, action);
    }
    catch (Exception ex)
    {
    if (!ADP.IsCatchableExceptionType(ex))
        throw;
    else
        ExceptionBuilder.TraceExceptionWithoutRethrow(ex);
    }
}

它调用其中之一:

DataRowCollection.ArrayAdd(DataRow row)
{
  row.RBTreeNodeId = this.list.Add(row);
}

DataRowCollection.ArrayInsert(DataRow row, int pos)
{
  row.RBTreeNodeId = this.list.Insert(pos, row);
}

this.list是 类型DataRowCollection.DataRowTree,派生自RBTree<DataRow>

private sealed class DataRowTree : RBTree<DataRow>

RBTree<DataRow>RBTreeNodeId让我们得出结论,正在使用红黑树!

于 2012-04-28T17:44:23.880 回答