ViV
ViV

Reputation: 2118

SelectedRows.Count vs Rows.GetRowCount(DataGridViewElementStates.Selected)

What is the difference between or is there any difference between:

myDgv.SelectedRows.Count 

vs

myDgv.Rows.GetRowCount(DataGridViewElementStates.Selected)

in the context of a DataGridView, Windows Forms ?

Upvotes: 2

Views: 3500

Answers (2)

Rob
Rob

Reputation: 4477

Microsoft suggest that SelectedCells and to a lesser extent SelectedRows are inefficient for large Data Sets, and that you should use GetCellCount/GetRowCount instead.

Upvotes: 1

Carth
Carth

Reputation: 2343

I think in the specific case you mention here there is very little difference between these two options aside from the order in which the data of your DataGridView will be processed. If you were saving off the intermediate objects that you're using to get the Count from you might be concerned that SelectedRows is presenting you with a static snapshot at the time that the reference is made but since both options are directly calling another method that shouldn't really be a factor here.

Whenever you're really curious about how to dig through something like this you can pop open ILDASM and browse into your GAC to see how the calls actually work.

From a somewhat high-level the distinction between using SelectedRows and Rows.GetCount() is that we're either getting a filtered collection and checking its size or getting the entire collection and filtering it down to a subset whose size we then retrieve. This is pretty much born out by what our IL for the initial usage shows us.

.method public hidebysig static void  testDG() cil managed
{
  // Code size       34 (0x22)
  .maxstack  2
  .locals init ([0] class [System.Windows.Forms]System.Windows.Forms.DataGridView dgvTest,
           [1] int32 myNum,
           [2] int32 otherum)
  IL_0000:  nop
  IL_0001:  newobj     instance void [System.Windows.Forms]System.Windows.Forms.DataGridView::.ctor()
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  callvirt   instance class [System.Windows.Forms]System.Windows.Forms.DataGridViewSelectedRowCollection [System.Windows.Forms]System.Windows.Forms.DataGridView::get_SelectedRows()
  IL_000d:  callvirt   instance int32 [System.Windows.Forms]System.Windows.Forms.BaseCollection::get_Count()
  IL_0012:  stloc.1
  IL_0013:  ldloc.0
  IL_0014:  callvirt   instance class [System.Windows.Forms]System.Windows.Forms.DataGridViewRowCollection [System.Windows.Forms]System.Windows.Forms.DataGridView::get_Rows()
  IL_0019:  ldc.i4.s   32
  IL_001b:  callvirt   instance int32 [System.Windows.Forms]System.Windows.Forms.DataGridViewRowCollection::GetRowCount(valuetype [System.Windows.Forms]System.Windows.Forms.DataGridViewElementStates)
  IL_0020:  stloc.2
  IL_0021:  ret
} // end of method Program::testDG

As you likely suspect though this kind of begs the question of what these two lower-level calls do.

In this case the Rows property on the DataGridView creates an instance of the DataGridViewsRowCollection and passes it back since it maps to get_Rows.

.method public hidebysig specialname instance class System.Windows.Forms.DataGridViewRowCollection 
        get_Rows() cil managed
{
  // Code size       27 (0x1b)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  ldfld      class System.Windows.Forms.DataGridViewRowCollection System.Windows.Forms.DataGridView::dataGridViewRows
  IL_0006:  brtrue.s   IL_0014
  IL_0008:  ldarg.0
  IL_0009:  ldarg.0
  IL_000a:  callvirt   instance class System.Windows.Forms.DataGridViewRowCollection System.Windows.Forms.DataGridView::CreateRowsInstance()
  IL_000f:  stfld      class System.Windows.Forms.DataGridViewRowCollection System.Windows.Forms.DataGridView::dataGridViewRows
  IL_0014:  ldarg.0
  IL_0015:  ldfld      class System.Windows.Forms.DataGridViewRowCollection System.Windows.Forms.DataGridView::dataGridViewRows
  IL_001a:  ret
} // end of method DataGridView::get_Rows

When we look at the SelectedRows property on the DataGridView we see that it's doing a lot more initially than just returning a collection but in the main try block we see our "get_Rows" call again (IL_0045).

.try
  {
    IL_0035:  br.s       IL_0056
    IL_0037:  ldloc.3
    IL_0038:  callvirt   instance object [mscorlib]System.Collections.IEnumerator::get_Current()
    IL_003d:  unbox.any  [mscorlib]System.Int32
    IL_0042:  stloc.1
    IL_0043:  ldloc.0
    IL_0044:  ldarg.0
    IL_0045:  call       instance class System.Windows.Forms.DataGridViewRowCollection System.Windows.Forms.DataGridView::get_Rows()
    IL_004a:  ldloc.1
    IL_004b:  callvirt   instance class System.Windows.Forms.DataGridViewRow System.Windows.Forms.DataGridViewRowCollection::get_Item(int32)
    IL_0050:  callvirt   instance int32 System.Windows.Forms.DataGridViewSelectedRowCollection::Add(class System.Windows.Forms.DataGridViewRow)
    IL_0055:  pop
    IL_0056:  ldloc.3
    IL_0057:  callvirt   instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
    IL_005c:  brtrue.s   IL_0037
    IL_005e:  leave.s    IL_0074
  }  // end .try

This suggests that we're doing the same retrieval and filtering operations for our two choices and that the "cost" of doing them could be reasonably expected to be the same.

If you're noting performance issues around these calls you could run some tests to see if there is a difference but based on the IL I would be surprised if you found any appreciable distinction between the two calls

Upvotes: 2

Related Questions