再编写PrefixTreeCache之前,我们可能还需要准备它的读取与写入功能。这两个操作其实都是对PrefixTreeVisitor的简单封装:
public class PrefixTreeCache<T> : IExpressionCache<T> where T : class
{
private Hashtable m_storage = new Hashtable();
private T Get(Expression key)
{
var visitor = new PrefixTreeVisitor(this.m_storage, true);
var storage = visitor.Accept(key);
return storage == null ? null : (T)storage[typeof(T)];
}
private void Set(Expression key, T value)
{
var visitor = new PrefixTreeVisitor(this.m_storage, false);
var storage = visitor.Accept(key);
storage[typeof(T)] = value;
}
}
现在编写IExpressionCache.Get方法已如探囊取物:
private ReaderWriterLockSlim m_rwLock = new ReaderWriterLockSlim();
public T Get(Expression key, Func<Expression, T> creator)
{
T value;
this.m_rwLock.EnterReadLock();
try
{
value = this.Get(key);
if (value != null) return value;
}
finally
{
this.m_rwLock.ExitReadLock();
}
this.m_rwLock.EnterWriteLock();
try
{
value = this.Get(key);
if (value != null) return value;
value = creator(key);
this.Set(key, value);
return value;
}
finally
{
this.m_rwLock.ExitWriteLock();
}
}
使用前缀树缓存方式,在已有n个对象的缓存容器中查询带有m个节点的表达式树,其时间复杂度正如之前所谈到那样为O(m)——与n无关。这个解决方案的缺点在于构造了大量的Hashtable,可能会导致整个前缀树处于一种非常稀疏的状态,这点可以通过自定义查找方式来替换直接使用Hashtable类进行优化。这属于纯粹的进一步实践,感兴趣的朋友可以自己尝试一下。
原文地址:http://www.cnblogs.com/jeffreyzhao/archive/2009/03/18/expression-cache-3-prefix-tree-cache.html