c# - 为 MemoryCache(或任何缓存)实现通用 Get<T>

标签 c# generics caching type-conversion memorycache

我正在尝试编写一个“简单” 通用 Get<T> ;扩展为 System.Runtime.MemoryCache .

为什么“简单”?因为通常我在缓存对象之前就知道对象的真实类型,所以当我从缓存中检索它时,我不会以不可预测的方式转换它。

例如:如果 boolean "true"值以 cacheKey "id"存储在缓存中,那么

Get<string>("id") == "true";
Get<int>("id") == 1; // any result > 0 is okay
Get<SomeUnpredictableType> == null; // just ignore these trouble conversions

这是我不完整的实现:

public static T DoGet<T>(this MemoryCache cache, string key) {
    object value = cache.Get(key);
    if (value == null) {
        return default(T);
    }
    if (value is T) {
        return (T)value;
    }

    // TODO: (I'm not sure if following logic is okay or not)
    // 1. if T and value are both numeric type (e.g. long => double), how to code it?
    // 2. if T is string, call something like Convert.ToString()

    Type t = typeof(T);
    t = (Nullable.GetUnderlyingType(t) ?? t);
    if (typeof(IConvertible).IsAssignableFrom(value.GetType())) {
        return (T)Convert.ChangeType(value, t);
    }
    return default(T);
}

非常感谢任何建议。

===================================

更新(2016 年 4 月 11 日):

对于给出的那些好的建议,我实现了我的第一个版本的 Get

public class MemCache {
    private class LazyObject<T> : Lazy<T> {
        public LazyObject(Func<T> valueFactory) : base(valueFactory) { }
        public LazyObject(Func<T> valueFactory, LazyThreadSafetyMode mode) : base(valueFactory, mode) { }
    }

    private static T CastValue<T>(object value) {
        if (value == null || value is DBNull) {
            return default(T);
        }
        Type valType = value.GetType();
        if (valType.IsGenericType && valType.GetGenericTypeDefinition() == typeof(LazyObject<>)) {
            return CastValue<T>(valType.GetProperty("Value").GetValue(value));
        }
        if (value is T) {
            return (T)value;
        }
        Type t = typeof(T);
        t = (Nullable.GetUnderlyingType(t) ?? t);
        if (typeof(IConvertible).IsAssignableFrom(t) && typeof(IConvertible).IsAssignableFrom(value.GetType())) {
            return (T)Convert.ChangeType(value, t);
        }
        return default(T);
    }

    private MemoryCache m_cache;

    public T Get<T>(string key) {
        return CastValue<T>(m_cache.Get(key));
    }

    public void Set<T>(string key, T value, CacheDependency dependency) {
        m_cache.Set(key, value, dependency.AsCacheItemPolicy());
    }

    public T GetOrAdd<T>(string key, Func<T> fnValueFactory, CacheDependency dependency) {
        LazyObject<T> noo = new LazyObject<T>(fnValueFactory, LazyThreadSafetyMode.ExecutionAndPublication);
        LazyObject<T> old = m_cache.AddOrGetExisting(key, noo, dependency.AsCacheItemPolicy()) as LazyObject<T>;
        try {
            return CastValue<T>((old ?? noo).Value);
        } catch {
            m_cache.Remove(key);
            throw;
        }
    }

    /* Remove/Trim ... */
}

最佳答案

基本工作是编写 CastValue 以将任何对象转换为所需类型。而且它不必处理非常复杂的情况,因为缓存中的对象类型对于程序员来说是可预测的。这是我的版本。

public static T CastValue<T>(object value) {
    if (value == null || value is DBNull) {
        return default(T);
    }
    if (value is T) {
        return (T)value;
    }
    Type t = typeof(T);
    t = (Nullable.GetUnderlyingType(t) ?? t);
    if (typeof(IConvertible).IsAssignableFrom(t) && typeof(IConvertible).IsAssignableFrom(value.GetType())) {
        return (T)Convert.ChangeType(value, t);
    }
    return default(T);
}

关于c# - 为 MemoryCache(或任何缓存)实现通用 Get<T>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36466490/

相关文章:

c# - 将 DataTable 从一个 DataSet 复制到另一个 DataSet

c# - 以编程方式安装 APK Xamarin.Forms (Android)

generics - 在 Rust 中接受 &Vec<T> 和 &Vec<&T> 的函数

c# - 如何使用泛型为多种数据类型创建通用的加法方法?

android - Android中ListView缓存的实现方法

caching - 使用 https 的 Drupal 模块 Boost,提取错误的缓存页面

c# - Visual Studio 中的 "Add existing item": is it possible to make "Add as link" default?

c# - 在 Windows Phone 8.1 中制作瘦 BottomAppBar

ios - swift (RxSwift) : Using generics to link ViewItem and Cell classes

caching - 在 Vert.x 中的 verticle 之间共享数据