3

DataTable.Rows.Add() は、データ テーブルに行を追加します。しかし、基になる配列をどのように処理するのでしょうか?

一度に 1 つの行を追加すると、行が追加されるたびに配列全体が再構築されますか?

それとも、パフォーマンスに影響を与えずに既存の配列を変更するだけでよいのでしょうか?

配列にデータを入力する前に配列のサイズを決定する方が良いのか、それともデータテーブルが (舞台裏で) コピーや移動をせずにコレクションを変更できるのか疑問に思っています。

配列を調整するには、配列を再定義し、既存のデータを新しい構造に移動する必要があることを理解しています。

私の質問は、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.listDataRowCollection.DataRowTreeから派生したタイプRBTree<DataRow>です。

private sealed class DataRowTree : RBTree<DataRow>

RBTree<DataRow>これにより、赤黒木が使用されているとRBTreeNodeId結論付けることができます!

于 2012-04-28T17:44:23.880 に答える