Sto cercando di scrivere un "semplice" Generico Get <T> estensione per System.Runtime.MemoryCacheImplementare Generico Get <T> per MemoryCache (o qualsiasi Cache)
Perché "semplice"? Perché generalmente conosco il tipo reale dell'oggetto prima di memorizzarlo nella cache, quindi quando lo recupero dalla cache, non lo convertirò in modi imprevedibili.
Per esempio: se booleano valore "vero" è memorizzato nella cache con cacheKey "id", in modo da
Get<string>("id") == "true";
Get<int>("id") == 1; // any result > 0 is okay
Get<SomeUnpredictableType> == null; // just ignore these trouble conversions
Ecco la mia L'implementazione incompleta:
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);
}
Tutti i suggerimenti sono molto apprezzati.
===================================
Aggiornamento (2016/04/11):
Per quei bei suggerimenti dati, implemento la mia prima versione di 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 ... */
}
È possibile utilizzare (T) Convert.ChangeType (valore, typeof (T)) ma questa sarebbe solo una parte del proprio metodo generico. –
Grazie, ho aggiunto al mio codice di esempio. Non sono ancora sicuro se ci sono alcune condizioni che ho perso nella sezione TODO. – ineztia
Scrivi test unitari, aggiungi tutti i casi che desideri gestire. –