从Object类型转换匿名类型

时间:2017-01-04 10:54:43

标签: c# .net generics memorycache

我正在尝试使用.NET 4.0中的System.Runtime.Caching.MemoryCache类。我有一个通用的方法,所以我可以将任何类型传递到内存缓存中并在调用时将其恢复。

该方法返回一个object类型的对象,该对象是一个匿名类型,其字段值包含缓存的对象。

我的问题是,如何将对象转换回相应的类型?

以下是我的代码......

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

和单元测试...

    [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)
        {

        }
    }

3 个答案:

答案 0 :(得分:4)

你做不到。匿名类型是......匿名的。它们没有您可以使用的类型名称,因此请改用类型。

当然,您仍然可以使用Reflection,但在这种情况下可能并不真正可用:

var x = ReturnObj.GetType().GetProperty("Value").GetValue(ReturnObj);

答案 1 :(得分:0)

您最好在整个地方使用泛型,而不仅仅是AddOrGetExisting<T>

另外,最好不要让Cache负责创建新对象。它应该是一个实用程序类,它应该遵循单一责任原则,它不应该有您的业务或数据层的链接。

作为一个例子,我将添加一个用于MVC的类。它不使用MemoryCache,而是使用HttpRuntime.Cache,因此它可能不是您需要的答案,但它可以指导您在使用泛型和单一责任原则方面找到更好的解决方案。

namespace Xyz.WebLibrary
{
    public static class Cache
    {
        // Get the value from the HttpRuntime.Cache that was stored using the cacheKey (if any). Returns true if a matching object of requested type T was found in the cache. Otherwise false is returned, along with a default(T) object or value.
        public static bool Get<T>(string cacheKey, out T result)
        {
            if (!string.IsNullOrEmpty(cacheKey))
            {
                object o = HttpRuntime.Cache.Get(cacheKey);
                if (o != null && o is T)
                {
                    result = (T)o;
                    return true;
                }
            }
            result = default(T);
            return false;
        }

        // Store a value in the HttpRuntime.Cache using the cacheKey and the specified expiration time in minutes.
        public static void Set(string cacheKey, object o, int slidingMinutes)
        {
            if (!string.IsNullOrEmpty(cacheKey) && slidingMinutes > 0)
                HttpRuntime.Cache.Insert(cacheKey, o, null, DateTime.MaxValue, TimeSpan.FromMinutes(slidingMinutes), CacheItemPriority.Normal, null);
        }

        // Erase the value from the HttpRuntime.Cache that was stored using the cacheKey (if any).
        public static void Erase(string cacheKey)
        {
            if (!string.IsNullOrEmpty(cacheKey) && HttpRuntime.Cache.Get(cacheKey) != null)
                HttpRuntime.Cache.Remove(cacheKey);
        }
    }
}

用法:

ProductInfo p;
int id = 12345;
string key = "ProductInfo_" + id;
if (!Cache.Get(key, out p))
{
    p = GetProductInfoFromDB(id);
    Cache.Set(key, p, slidingMinutes: 5);
}

答案 2 :(得分:0)

  

我的问题是,如何将我正在重新投入的对象投射到其中   相应的类型?

你不能这样做!从高级/语义的角度来看,匿名类型是匿名(即你不能转换为未知类型,可以吗?),它们是内部的,并且具有来自a的随机名称低级别的观点。也就是说,他们无法访问

我可以建议你两种方法:

救援的动态对象

在您的问题中,您说您无法访问object的属性,但您可以实现一个简单的DynamicObject来动态访问任何对象属性:

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

使用整个包装器如下:

var obj = new { Text = "hello world" };

dynamic dynObj = new DynamicWrapper(obj);
string text = dynObj.Text;

结论

  • 存储和检索包含DynamicWrapper之类的缓存对象,它将按预期工作!

  • 否则请使用词典。

  • 或者,就像其他回答者已经说过的那样,不要使用匿名类型并存储具体类型。