What we were left with was a pretty simple method, but I think it could be made even more readable with a few tweaks. Here’s the code as it is after my changes:
private static void BuildCatalog()
{
OnIndexBuilding();
bool commentsEnabled = BlogSettings.Instance.EnableCommentSearch;
lock (_SyncRoot)
{
_Catalog.Clear();
foreach (Post post in Post.PublishedPosts)
{
AddItem(post);
if (commentsEnabled)
{
foreach (Comment comment in post.ApprovedComments)
{
AddItem(comment);
}
}
}
foreach (Page page in Page.PublishedPages)
{
AddItem(page);
}
}
OnIndexBuild();
}
There are a three foreach() blocks working on List<> objects, and within each block there’s a single line of code. That kind of code is just begging to be made a bit more elegant.
The .NET Framework 2.0 added the List.ForEach() method, which allowed for something like:
post.ApprovedComments.ForEach(delegate(Comment comment)
{
AddItem(comment);
}
Using a delegate, this syntax isn’t substantially better nor easier to read. However, toss in a lambda expression instead (introduced by .NET Framework 3.0), and ForEach() suddenly becomes juicily delicious:
post.ApprovedComments.ForEach(comment => AddItem(comment));
Yummy. All that blocky wordiness condensed to a simple, readable, one-line statement. Once we sprinkle those into our BuildCatalog() method, we may end up with something like:
private static void BuildCatalog()
{
OnIndexBuilding();
lock (_SyncRoot)
{
_Catalog.Clear();
if (BlogSettings.Instance.EnableCommentSearch)
{
Post.PublishedPosts.ForEach(post => AddPostAndComments(post));
}
else
{
Post.PublishedPosts.ForEach(post => AddItem(post));
}
Page.PublishedPages.ForEach(page => AddItem(page));
}
OnIndexBuild();
}
Much cleaner code, I think. My final version of the Catalog class, after extracting it from the Search.cs file and adding a few more refactorings (like an extension method or two), looks like this:
public static class Catalog
{
private static List<Entry> entries = new List<Entry>();
private readonly static object syncRoot = new object();
internal static List<Entry> Entries
{
get { return entries; }
}
internal static void AddItem(IPublishable item)
{
item.AddToCatalog();
}
internal static void Build()
{
OnIndexBuilding();
lock (syncRoot)
{
entries.Clear();
Page.PublishedPages.ForEach(page => page.AddToCatalog());
if (BlogSettings.Instance.EnableCommentSearch)
{
Post.PublishedPosts.ForEach(post => post.AddSelfAndCommentsToCatalog());
}
else
{
Post.PublishedPosts.ForEach(post => post.AddToCatalog());
}
}
OnIndexBuilt();
}
private static void AddSelfAndCommentsToCatalog(this Post post)
{
post.AddToCatalog();
post.ApprovedComments.ForEach(c => c.AddToCatalog());
}
private static void AddToCatalog(this IPublishable item)
{
var entry = new Entry
{
Item = item,
Title = TextAgent.CleanContent(item.Title, false),
Content = HttpUtility.HtmlDecode(TextAgent.CleanContent(item.Content, true))
};
if (item is Comment)
{
entry.Content += HttpUtility.HtmlDecode(TextAgent.CleanContent(item.Author, false));
}
entries.Add(entry);
}
public static event EventHandler<EventArgs> IndexBuilding;
private static void OnIndexBuilding()
{
if (IndexBuilding != null)
{
IndexBuilding(null, EventArgs.Empty);
}
}
public static event EventHandler<EventArgs> IndexBuilt;
private static void OnIndexBuilt()
{
if (IndexBuilt != null)
{
IndexBuilt(null, EventArgs.Empty);
}
}
}
No comments:
Post a Comment
Please leave a comment. You can use some HTML tags, such as <b>, <i>, <a>