Wheeee

Published January 26, 2010
Advertisement
There's a horribly subtle little bug here. Can you spot it?

public IEnumerable GetContentItemHeaders(IEnumerable uris, ContentItemHeader.Fields fieldsToGet, int actorSid)        {            using (var context = new ArticlesDataContext())            {                return uris.Select(delegate(Uri u)                                            {                                                var identifier = PrefixUri.MakeRelativeUri(u).ToString();                                                try {                                                     var g = new Guid(identifier);                                                    return context.articles.Where(a => a.ID == g).FirstOrDefault();                                                }                                                catch (FormatException)                                                {                                                    return context.articles.Where(a => a.UrlTitle == identifier).FirstOrDefault();                                                }                                            })                                            .Where(g => g != null)                                            .Select(g => new ContentItemHeader                                                             {                                                                 ObjectSID=0,                                                                 SerializedData=GetSerializedArticleHeader(g),                                                                 Uri= new Uri(PrefixUri, g.UrlTitle)                                                             });            }        }


(Hint: It manifests as an ObjectDisposedException).
0 likes 5 comments

Comments

Mike.Popoloski
Your LINQ methods are all deferred execution and don't activate until you first enumerate the result of the method, at which point the ArticlesDataContext has already been disposed [grin]

Just out of curiosity, why do you use the anonymous delegate syntax instead of a lambda expression?
January 26, 2010 04:03 PM
superpig
Cookie for you.

I don't like using lambdas for things that are best expressed as multiple statements - a holdover from my training as a functional programmer, I guess. If I'm going to go functional, I go fully functional.
January 27, 2010 07:05 PM
Trillian
Now that we know the problem, what's the fix? You could force the execution of the query with a ToList() or similar, but if the deferred execution was intended, the only way I can think of implementing it is to code your own IEnumerable<ContentItemHeader> and IEnumerator<ContentItemHeader>, create your ArticlesDataContext in IEnumerable<ContentItemHeader>.GetEnumerator and dispose it in IEnumerator<ContentItemHeader>.Dispose. But that seems to be a lot of trouble...
January 30, 2010 07:48 AM
superpig
The deferred execution wasn't a big deal in this case, so I did just stick a .ToList() on the end.

If the deferred execution was desired, the using() statement would have to go; context.Dispose() would need to be called at the end of deferred evaluation. Some way of annotating the final element in the sequence with a call to context.Dispose() would probably be coolest.
February 01, 2010 11:39 AM
Mike.Popoloski
Extension methods to the rescue!


public static IEnumerable<TSource> Using<TSource>(this IEnumerable<TSource> source, params IDisposable[] trash)
{
    foreach (var item in source)
        yield return item;

    foreach (var item in trash)
        item.Dispose();
}



Now you just tack this on at the end of your LINQ expression and you're good to go.
February 01, 2010 05:31 PM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Profile
Author
Advertisement
Advertisement