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
結論付けることができます!