Does iterating through SPList.Items using foreach affect performance?

Iterating through SPList.Items using a for (int i) loop is bad for performance, as each call to SPList.Items causes a trip to the DB and will retrieve all items. See http://blog.dynatrace.com/2009/01/11/the-wrong-way-to-iterate-through-sharepoint-splist-items/.

I have always wondered whether using a foreach loop would cause the same issue.

I decided to use TypeMock to find out. My plan is to create a fake list, then setup the fakeList.Items property so that when called, it will invoke a substitute method instead. This substitute method will increment a count each time it is invoked, and return the fakeList.Items property.

Here is my setup code.

int itemsCallCount = 0;
SPListItemCollection itemCollection;

[TestMethod]
public void TestMethod1()
{
	//Create a fake list 
	var fakeList = Isolate.Fake.Instance<SPList>();

	//Setup the fakeList.Items so that when fakeList.Items.GetEnumerator() is called, 3 items will be returned. 
	//This is because GetEnumerator() is what will be called in the foreach loop.

	SPListItem[] items = new SPListItem[3];
	IsolateFaker.FakeEnumeratorElements<SPListItem>(fakeList.Items, items);

	//Setup the fakeList.Items.Count also. This is what will be used in the for (int i) loop.
	Isolate.WhenCalled(() => fakeList.Items.Count).WillReturn(3);

	//Save the setup of fakeList.Items. This is what we will return in our substitue tracking method.
	itemCollection = fakeList.Items;

	//Hook in our substitue method so we can track the calls to fakeList.Items.
	Isolate.WhenCalled(() => fakeList.Items).DoInstead((context) => ReturnItemCollectionAndTrackCount(context));
}

private SPListItemCollection ReturnItemCollectionAndTrackCount(MethodCallContext context)
{
	itemsCallCount++;
	return itemCollection;
}

IsolateFaker.FakeEnumeratorElements() is a helper method I wrote that is not included here for brievity.

Here is my test target:

public int IterateUsingForEach(SPList list) 
{ 
	int count = 0; 
	foreach (SPListItem item in list.Items) 
	{ 
		var temp = item; 
		count++; 
	} 
	return count; 
}

public int IterateUsingForInt(SPList list)
{       
	int count = 0;
	for (int i = 0; i < list.Items.Count; i++)       
	{         
		var temp = list.Items[i];         
		count++;       
	}       
	return count;     
}

Here is my actual unit test method:

//Test using foreach. This will pass.         
Target target = new Target();       
Assert.AreEqual(3, target.IterateUsingForEach(fakeList));
Assert.AreEqual(1, itemsCallCount);

//Test using for (int i). This will fail.
itemsCallCount = 0;       
Target target2 = new Target();
Assert.AreEqual(3, target2.IterateUsingForInt(fakeList));
Assert.AreEqual(1, itemsCallCount);

So what’s the conclusion? Foreach invokes the Items property once. For (int i) invokes the Items property 7 times. This means using Foreach does not cause the performance issue as for (int i) would.

Heck, if you know the CLR/MSIL well enough you probably already know the answer – but nevertheless it was interesting to play around with the Typemock stuff :D.

Advertisement

About Bernado

Based in Australia, I am a freelance SharePoint and Dynamics CRM developer. I love developing innovative solutions that address business and everyday problems. Feel free to contact me if you think I can help you with your SharePoint or CRM implementation.
This entry was posted in SharePoint, TypeMock. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s