【发布时间】:2011-07-08 13:15:50
【问题描述】:
在 WCF 客户端应用程序中,有许多我们希望缓存结果的无参数方法 - GetAllFoo()、GetAllBar()。这些用于填充下拉列表等,并且结果在客户端的运行期间不会改变。
这些结果当前由存储在资源文件中的唯一字符串缓存 - 例如,GetAllCountries() 针对CountryKey 资源进行缓存。仅当缓存不包含请求的键时才调用该服务。
public T Get<T, V>(string key, Func<V, T> serviceCall, V proxy)
{
if (!cache.Contains(key))
{
cache.Add(key, serviceCall(proxy));
}
return cache.GetData(key) as T;
}
这很好,除了我们需要维护资源文件中的键,并且需要确保每个方法都使用正确的缓存键,否则事情会中断。旧的 Control+C,Control+V 在这里引起了一些头疼,我不想去检查每个调用这个方法的地方。
那么问题来了:
serviceCall 委托上有一个 Method 属性,它描述了要执行的方法。这是一个 MethodInfo 实例,它又包含一个 MethodHandle 属性。我是否正确假设 MethodHandle 属性唯一且一致地标识所引用的方法?
我会将包装器更改为
public T Get<T, V>(Func<V, T> serviceCall, V proxy)
{
var key = serviceCall.Method.MethodHandle;
// etc
它正确封装了缓存和关键问题,并消除了对调用者“做正确的事”的任何依赖。
- 不要关心 MethodHandle 是否在实例之间发生变化 - 缓存仅针对每个实例
- 不要关心 MethodHandle 是否在客户端之间不一致 - 缓存是每个客户端的
- 请注意 MethodHandle 在客户端实例中是否不一致 - 我实际上希望使用缓存,而不是每次请求都会导致新的服务调用并且缓存中充满未使用的数据
- 请注意 MethodHandle 在客户端实例中是否不是唯一的 - 我必须确保在使用包装器时返回正确的数据(和类型)。
【问题讨论】:
-
据我所知 MethodHandle 是一个元数据的东西,所以它可以在编译时改变吗?我不确定....消除这种可能性的另一种方法是在启动时或第一次调用时构建缓存,并在适当的情况下为缓存使用具有适当锁定的静态变量。如您所示,我将使用抽象调用的包装器,允许您的实现更改。
-
为什么不使用 MethodInfo 本身而不是 MethodHandle?额外的间接级别似乎是不必要的。但要回答您的问题,MethodInfo 和 RuntimeMethodHandle 对于各个方法都是唯一的,并且在获得它们的 AppDomain 的生命周期内都是稳定的。
-
补充一下 Levi 所说的,MethodHandles 跨应用程序域无效。不太可能发挥作用,但我想我会加入。
标签: c# .net caching reflection methodinfo