【问题标题】:Casting anonymous type from type Object [duplicate]从对象类型转换匿名类型[重复]
【发布时间】:2017-01-04 10:54:43
【问题描述】:

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

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

我的问题是,我怎样才能将我得到的对象转换回其对应的类型?

下面是我的代码……

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

        }
    }

【问题讨论】:

  • 答案是:不要为此使用匿名类型,使用适当的命名类型。
  • 解决办法是声明一个类型。
  • 匿名类型可作为internal 访问,这意味着您必须添加一个程序集属性以使用属性InternalsVisibleToAttribute 向测试项目公开内部类型。
  • 在同一个程序集中,可能有....“hacks”,但跨程序集,不行。使用正确的命名类型。

标签: c# .net generics memorycache


【解决方案1】:

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

当然,您仍然可以使用反射,但在这种情况下可能无法真正使用:

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

【讨论】:

    【解决方案2】:

    我的问题是,我怎样才能将我要返回的对象投射到它的 对应的类型?

    你不能这样做!从高级/语义的角度来看,匿名类型是 anonymous(也就是说,您不能转换为未知类型,对吗?),它们是内部的,并且具有来自低层次的观点。也就是说,它们无法访问

    我可以建议你两种方法:

    救援动态对象

    在您的问题中,您说您无法访问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 之类的东西包装的缓存对象,它会按您的预期工作!

    • 否则使用字典。

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

    【讨论】:

      【解决方案3】:

      您最好在所有地方都使用泛型,而不是只用于AddOrGetExisting&lt;T&gt;

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


      作为示例,我将添加一个用于 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);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-11-27
        • 1970-01-01
        • 2011-04-19
        • 1970-01-01
        相关资源
        最近更新 更多