2016-04-07 15 views
8

Ich versuche, ein "einfache" Generisches Get für <T> Erweiterung System.Runtime.MemoryCache zu schreibenImplementieren Generisches Get <T> für Memory (oder einem Cache)

Warum "simple"? Da ich den realen Typ des Objekts im Allgemeinen kenne, bevor ich es zwischenspeichern kann, werde ich es, wenn ich es aus dem Cache abrufe, nicht auf unvorhersehbare Weise konvertieren.

Zum Beispiel: Wenn boolean Wert "true" im Cache mit CacheKey "id" gespeichert ist, so

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

Hier ist meine unvollständig UMSETZUNG:

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

Irgendwelche Vorschläge sehr geschätzt werden.

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

Update (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; 
} 

Usage (annehmen:

Für jene nette Anregungen gegeben, ich meine erste Version von Get <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

Sie könnten (T) Convert.ChangeType (Wert, Typof (T)) verwenden, aber dies wäre nur ein Teil Ihrer sehr generischen Methode. –

+0

Danke, ich habe meinen Beispielcode hinzugefügt. Ich bin mir immer noch nicht sicher, ob es einige Bedingungen gibt, die ich in der TODO-Sektion verpasst habe. – ineztia

+0

Schreiben Sie Komponententests, fügen Sie alle Fälle hinzu, die Sie behandeln möchten. –

Antwort

1

Die wesentliche Arbeit besteht darin, einen CastValue <T> zu schreiben, um jedes Objekt in den gewünschten Typ zu konvertieren. Und es muss nicht sehr komplizierten Zustand behandeln, weil Objekttypen im Cache für den Programmierer vorhersehbar ist. Und hier ist meine Version.

2

Vorschlag implementieren d Sie haben eine ID vom Typ int im Cache):

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

ich es nicht getestet.

+0

Es scheint, dass einige Bedingungen fehlen, da Sie davon ausgehen, dass der Wert immer (T) zurückgegeben werden kann. Ich habe getestet und die Ausnahme "Angegebener Cast ist nicht gültig" erhalten. – ineztia

+0

Was haben Sie dem Cache hinzugefügt, was haben Sie daraus gelesen? –

+0

Zahlen, Texte oder andere schwer geladene Objekte (Entitäten) @StefanSteinegger – ineztia