views:

452

answers:

3

After reading Stefan Gossner's post about disposing objects and this question about Cross method dispose patterns, I found that I was guilty of accidentally reopening some SPWebs. I know in Stefan Gossner's post he mentions you should dispose of an SPWeb after you are finished with any child object. However, the microsoft documentation mentions Caching the SPListItemCollection object. Is the following code correct? Would the returned SPListItemCollection reopen an SPWeb object? Is there any way to tell for sure?

// is this correct????
private SPListItemCollection GetListItems()
{
    SPListItemCollection items = null;
    try
    {
        using (SPSite site = new SPSite(GetListSiteUrl()))
        {
            using (SPWeb web = site.OpenWeb())
            {
                // retrieve the list
                SPList list = web.Lists[_ListName];

                // more code to create the query...
                items = list.GetItems(query);
            }
        }
    }
    catch (Exception e)
    {
        // log error
    }
    return items;
}

Edit 09/09/09

I am mainly referring to this part of Stefan Grossner's post:

You should dispose a SPWeb or SPSite object after the last access to a child object of this object.

I believe what he is saying is that if I use the SPListItemCollection after I dispose of the SPWeb that I used to get it... the SPWeb will be reopened automatically.

+1  A: 

As far as I know the answer is no, but I would have written the code something like

private void FetchItems(Action<SPListItemCollection> action)
{
   using(...)
   {
       var items = list.GetItems(query);
       action(items);
   }
}

By doing this, to call this method you would need to send a method along (delegate) that the SPListItemCollection should be used for, an example:

FetchItems( items => ....) or FetchItems( DoStuffWithItems(SPListItemCollection) )

Johan Leino
I could probably do it using Action<> but I don't think the action would ever change... I think that defeats the purpose of Action<>? I probably just need to move all of the code using the SPListItemCollection inside of the GetListItems() function just to be safe.
Kit Menke
A: 

If you are talking about whether you need an SPWeb in the same scope when you get around to using the SPListItemCollection, I think the answer is no.

For example, I routinely do the following:

    private IEnumerable<SPListItem> AllItems;

    public void GetItems()
    {
        var results = SPContext.Current.Web.Lists[ListName].Items.Cast<SPListItem>();
        this.AllItems = results;
    }

and then I use AllItems all over the place, and it works fine.

Incase you are wondering, the cast is done so I can use Linq on the result set - much much faster than submitting a query to the list, especially if you are doing multiple subselects on the data.

Moo
Unfortunately, I only have access to Visual Studio 2005 and I don't think that I will be able to use Linq. I do like your method of returning the SPListItems. However, my question is not whether you NEED an SPWeb, but whether another one will be opened automatically that will need to be disposed.
Kit Menke
Ahh, as far as I am aware, no, one isn't created as once you get the items they are all self contained.
Moo
Also, if you won't be using Linq, you could just store the collection as an SPListItemCollection and do a foreach(SPListItem MyItem in ListItems) {} loop on them
Moo
I went straight to the source and found out that the SPListItemCollection CAN reopen an SPWeb. This means that if you do return an SPListItemCollection, dispose your SPWeb, and then use the SPListItemCollection somewhere else... your SPWeb you disposed can get reopened. Check your code as you may be having memory issues and not know it!
Kit Menke
+2  A: 

I found out after asking Stefan directly that the SPListItemCollection can indeed reopen the SPWeb after you dispose of it. This means that my code posted above is INCORRECT and I would only be able to dispose of the SPWeb after I use the SPListItemCollection.

Kit Menke