I've previously used the RealProxy for this type of functionality. I've shown some examples in my blog post; Intercepting method invocations using RealProxy.
A quick example of a caching proxy, using the hash code of the method (to ensure that two different methods with same arguments are cached separately) and the arguments. Note that there's no handling of out-parameters, only the return value. (You would need to change the _cache
to hold an object that contains both return value and output parameters if you want to change this.) Also, there's no form av thread safety with this implementation.
public class CachingProxy<T> : ProxyBase<T> where T : class {
private readonly IDictionary<Int32, Object> _cache = new Dictionary<Int32, Object>();
public CachingProxy(T instance)
: base(instance) {
}
protected override IMethodReturnMessage InvokeMethodCall(IMethodCallMessage msg) {
var cacheKey = GetMethodCallHashCode(msg);
Object result;
if (_cache.TryGetValue(cacheKey, out result))
return new ReturnMessage(result, msg.Args, msg.ArgCount, msg.LogicalCallContext, msg);
var returnMessage = base.InvokeMethodCall(msg);
if (returnMessage.Exception == null)
_cache[cacheKey] = returnMessage.ReturnValue;
return returnMessage;
}
protected virtual Int32 GetMethodCallHashCode(IMethodCallMessage msg) {
var hash = msg.MethodBase.GetHashCode();
foreach(var arg in msg.InArgs) {
var argHash = (arg != null) ? arg.GetHashCode() : 0;
hash = ((hash << 5) + hash) ^ argHash;
}
return hash;
}
}