将类型为Object的对象转换为匿名类型。
将类型为Object的对象转换为匿名类型。
我正在尝试在.NET 4.0中利用System.Runtime.Caching.MemoryCache类。我有一个通用方法,可以将任何类型传递到内存缓存中,并在调用时获取回来。\n该方法返回一个对象,类型为object,其中包含缓存对象的字段Value。\n我的问题是,我如何将获取到的对象强制转换为其对应的类型?\n以下是我的代码...\n
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(string key, Func valueFactory) { var newValue = new Lazy (valueFactory); var oldValue = _cache.AddOrGetExisting(key, newValue, new CacheItemPolicy()) as Lazy ; try { return (oldValue ?? newValue).Value; } catch { _cache.Remove(key); throw; } } /// /// 如何访问Value并将其强制转换为类型 "List /// ///" /// private static object InitialiseItem(string key) { // SearchVehicleData.GetAllMakes(false) 的类型是 List return new { Value = SearchVehicleData.GetAllMakes(false) }; } }
\n以及单元测试...\n
[TestMethod] public void TestGetAllMakes_Cached() { dynamic ReturnObj = ObjectCache.GetItem("GetAllMakes"); // ********************************************* // 由于测试者的类型是Object且没有Value字段,所以无法这样做 foreach(IBrowseStockVehicle item in ReturnObj.Value) { } }
在使用缓存时,我们需要将对象存储到缓存中并在需要时从缓存中获取。在这个过程中,可能会遇到将匿名类型从对象类型转换的问题。下面我们来看一下这个问题出现的原因以及解决方法。
在上述代码中,我们可以看到一个名为Cache的实用类,它使用了HttpRuntime.Cache来存储和获取缓存对象。在这个类中,有一个Get方法用于从缓存中获取对象,并将其转换为指定的类型T。这里使用了对象类型Object来存储缓存对象,而不是使用泛型来指定类型。
然而,在进行类型转换时,可能会遇到将匿名类型从对象类型转换的问题。在代码中,我们可以看到在转换之前,使用了is关键字来检查对象是否属于类型T。如果不属于,就会返回false,并返回默认值。这就是出现问题的地方。
为了解决这个问题,我们可以使用泛型来指定类型T,而不是使用对象类型Object。这样,我们就可以避免将匿名类型从对象类型转换的问题。同时,我们还可以在获取缓存对象时使用泛型方法来指定类型T,以避免在代码中进行类型转换。
下面是修改后的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(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, T 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); } } }
上述代码中,我们将Get方法和Set方法改为了泛型方法,使用泛型来指定类型T。这样,我们就可以在使用Cache类时,指定需要获取的对象的类型。例如,我们可以使用以下代码来从缓存中获取ProductInfo类型的对象:
ProductInfo p; int id = 12345; string key = "ProductInfo_" + id; if (!Cache.Get(key, out p)) { p = GetProductInfoFromDB(id); Cache.Set(key, p, slidingMinutes: 5); }
在上述代码中,我们首先尝试从缓存中获取ProductInfo类型的对象。如果获取失败,则从数据库中获取对象,并将其存储到缓存中。这样,我们就避免了将匿名类型从对象类型转换的问题,并且可以更方便地使用缓存功能。
,将匿名类型从对象类型转换的问题可以通过使用泛型来解决。通过将获取缓存对象的方法改为泛型方法,并在使用缓存时指定对象的类型,我们可以避免类型转换的问题,并更方便地使用缓存功能。
从上述内容中可以整理出以下问题的出现原因和解决方法:
问题:如何将获取到的对象转换为对应的类型?
原因:无法进行此操作!匿名类型在高层次/语义层面上是匿名的(即你不能转换为未知类型,对吧?),并且在低层次上是不可访问且具有随机名称的。也就是说,它们是不可访问的。
解决方法:
1. 将整个对象转换为字典,并使用键访问其属性。可以参考之前的一些回答,这些回答对于像你这样的简单情况可能很有用:将对象映射为字典以及如何将类转换为Dictionary
2. 使用动态对象。
动态对象的解决方法如下:
public sealed class DynamicWrapper : DynamicObject { public DynamicWrapper(object target) { Target = target; // 我们将属性名称和属性元数据存储在字典中,以便后续加速(我们可以使用时间复杂度O(1)查找是否存在所请求的属性!) TargetProperties = target.GetType() .GetProperties(BindingFlags.Instance | BindingFlags.Public) .ToDictionary(p => p.Name, p => p); } private IDictionaryTargetProperties { get; } private object Target { get; } public override bool TrySetMember(SetMemberBinder binder, object value) { // 不支持设置属性! 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`的东西中,它将按照你的预期工作!
- 或者使用字典。
- 或者,正如其他回答者已经提到的,不要使用匿名类型,而是存储具体类型。
在这个问题中,无法将类型为Object的对象强制转换为匿名类型(Casting anonymous type from type Object)。匿名类型是没有类型名称的,因此无法直接进行类型转换。
然而,仍然可以使用反射来实现该功能,但在这种情况下,这可能不是一个真正可用的解决方法。下面是一个示例代码:
var x = ReturnObj.GetType().GetProperty("Value").GetValue(ReturnObj);
在这个示例中,`ReturnObj`是一个类型为Object的对象。通过使用反射,我们可以使用`GetType()`方法获取其实际类型,然后使用`GetProperty()`方法获取名为"Value"的属性,最后使用`GetValue()`方法获取该属性的值。这样我们就可以得到一个类型为Object的对象,但是无法直接将其转换为匿名类型。
然而,使用反射来处理这个问题可能会导致代码变得复杂和难以维护。如果可能的话,建议考虑使用其他方法来解决类型转换的问题,例如使用具有已知类型的对象,或者通过修改代码结构来避免需要进行此类型转换的情况。