2016-04-07 43 views
8

MemoryCache (veya herhangi Cache) için alın uygulamak? Çünkü genellikle önbelleğe almadan önce nesnenin gerçek tipini biliyorum, bu yüzden önbellekten aldığımda, bunu tahmin edilemez yollarla değiştirmeyeceğim. Örneğin Jenerik Ben <strong>"basit"</strong> Jenerik System.Runtime.MemoryCache</p> <p>için <T> uzatma Neden "basit" Get yazmaya çalışıyorum

: Herhangi bir öneri son derece takdir edilmektedir

pubic 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); 
} 

: boolean "true" değeri cacheKey "id" önbellekte saklanır eğer, bu nedenle

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

İşte benim eksik Gerçekleştiren bu.

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

Güncellemesi (2016/04/11):

pubic static T DoGet<T>(this MemoryCache cache, string key) 
{ 
    object value = cache.Get(key); 
    if (value == null) { 
     return default(T); 
    } 
    // support for nullables. Do not waste performance with 
    // type conversions if it is not a nullable. 
    var underlyingType = Nullable.GetUnderlyingType(t); 
    if (underlyingType != null) 
    { 
     value = Convert.ChangeType(value, underlyingType); 
    } 
    return (T)value; 
} 

Kullanımı (varsayalım:

verilenlerden güzel öneriler için ben <T>

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 ... */ 
} 
+1

(T) Convert.ChangeType (value, typeof (T)) kullanabilirsiniz, ancak bu çok genel yönteminizin bir parçası olacaktır. –

+0

Teşekkürler, örnek koduma ekledim. TODO bölümünde kaçırdığım bazı koşulların olup olmadığından emin değilim. – ineztia

+0

Birim testleri yazın, işlemek için istediğiniz tüm durumları ekleyin. –

cevap

1

temel iş istenen tipine herhangi bir nesne dönüştürmek için bir CastValue <T> yazmak. Ve çok karmaşık bir durumla başa çıkmak zorunda değil çünkü önbellekteki nesne türleri programcı için tahmin edilebilir. Ve işte benim versiyonum.

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); 
} 
2

Öneri Get benim ilk versiyonunu uygulamak d siz) önbelleğinde tip int bir kimliğe sahip:

int id = Get<int>("id"); 
int? mayBeId = Get<int?>("id"); 
string idAsString = Get<int?>("id")?.ToString(); 
double idAsDouble = (double)Get<int>("id"); 

bunu test etmedi.

+0

Bazı koşullar eksik gibi görünüyor, her zaman (T) değeri döndürebilir varsayalım. Test ettim ve "Belirtilen yayın geçerli değil" istisnasını aldım. – ineztia

+0

Önbelleğe ne eklediniz, neyi okumaya çalıştınız? –

+0

sayıları, metinleri veya herhangi bir ağır yüklü nesnesi (varlık) @StefanSteinegger – ineztia

İlgili konular