I’m trying to utilise the System.Runtime.Caching.MemoryCache class in .NET 4.0. I have a method that is generic so I can pass any type into the memory cache and get it back when invoked.
The method returns an object of type object which is an anonymous type with a field Value which contains the cached object.
My question is, how can I cast the object I’m getting back into its corresponding type?
Below is my code…
public static class ObjectCache
{
private static MemoryCache _cache = new MemoryCache("GetAllMakes");
public static object GetItem(string key)
{
return AddOrGetExisting(key, () => InitialiseItem(key));
}
private static T AddOrGetExisting<T>(string key, Func<T> valueFactory)
{
var newValue = new Lazy<T>(valueFactory);
var oldValue = _cache.AddOrGetExisting(key, newValue, new CacheItemPolicy()) as Lazy<T>;
try
{
return (oldValue ?? newValue).Value;
}
catch
{
_cache.Remove(key);
throw;
}
}
/// <summary>
/// How can i access Value and cast to type "List<IBrowseStockVehicle>"
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
private static object InitialiseItem(string key)
{
// SearchVehicleData.GetAllMakes(false) is of type List<IBrowseStockVehicle>
return new { Value = SearchVehicleData.GetAllMakes(false) };
}
}
and the unit test...
[TestMethod]
public void TestGetAllMakes_Cached()
{
dynamic ReturnObj = ObjectCache.GetItem("GetAllMakes");
// *********************************************
// cannot do this as tester is of type Object and doesnt have teh field Value
foreach(IBrowseStockVehicle item in ReturnObj.Value)
{
}
}
My question is, how can I cast the object I’m getting back into its corresponding type?
You can't do this! Anonymous types are anonymous from a high-level/semantic point of view (i.e. you can't cast to an unknown type, can you?), and they're internal and with a random name from a low level point of view. That is, they're inaccessible.
I can suggest you two approaches:
Convert the whole object to a dictionary and access its properties using keys. Some answers I did a long time ago should be useful on this case for simpler cases like yours: Mapping object to dictionary and vice versa and How to convert class into Dictionary<string,string>?
Dynamic objects to the rescue!
In your question you said that you can't access a property of object
, but you can implement a simple DynamicObject
to access any object property dynamically:
public sealed class DynamicWrapper : DynamicObject
{
public DynamicWrapper(object target)
{
Target = target;
// We store property names and property metadata in a dictionary
// to speed up things later (we'll find if a requested
// property exists with a time complexity O(1)!)
TargetProperties = target.GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.ToDictionary(p => p.Name, p => p);
}
private IDictionary<string, PropertyInfo> TargetProperties { get; }
private object Target { get; }
public override bool TrySetMember(SetMemberBinder binder, object value)
{
// We don't support setting properties!
throw new NotSupportedException();
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
PropertyInfo property;
if(TargetProperties.TryGetValue(binder.Name, out property))
{
result = property.GetValue(Target);
return true;
}
else
{
result = null;
return false;
}
}
}
And use the whole wrapper as follows:
var obj = new { Text = "hello world" };
dynamic dynObj = new DynamicWrapper(obj);
string text = dynObj.Text;
Store and retrieve your cached object wrapped with something like DynamicWrapper
and it will work as you expect!
Otherwise use dictionaries.
Or, like other answerers have already said, don't use anonymous type and store concrete types.