2014-10-03 190 views
5

我试图为一个字节[] - > RedisValue转换为Strathweb.CacheOutput.WebApi2创建一个Redis提供程序, > byte []返回null。StackExchange.Redis将RedisValue转换为byte []通过“as byte []”返回null

我可以手动将对象类型设置为byte []而不是var/RedisValue,它将正确地将该值作为byte []返回,但是在将其设置为RedisValue后,其无法将其转换为字节[]。

他的接口有Get始终返回一个对象,所以我不能强制类型或使用单独的调用而不必修改接口。

如果我尝试做一个result as byte[]我得到 Cannot convert type 'StackExchange.Redis.RedisValue' to 'byte[]' via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversion

如果我尝试做一个(byte[])result我得到Cannot cast 'result' (which has an actual type of 'StackExchange.Redis.RedisValue') to 'byte[]'

有我丢失的东西还是我将不得不破解它以某种方式通过检查基于密钥寻找哪种类型的数据?

这里的接口:

namespace WebApi.OutputCache.Core.Cache 
{ 
    public interface IApiOutputCache 
    { 
     void RemoveStartsWith(string key); 
     T Get<T>(string key) where T : class; 
     object Get(string key); 
     void Remove(string key); 
     bool Contains(string key); 
     void Add(string key, object o, DateTimeOffset expiration, string dependsOnKey = null); 
     IEnumerable<string> AllKeys { get; } 
    } 
} 

这里是其所谓的如何:

 var val = _webApiCache.Get(cachekey) as byte[]; 
     if (val == null) return; 

编辑:API的实例添加我实现同时使用ServiceStack.Redis V3(因为它ATM工作只是使用object和StackExchange.Redis不工作)

https://github.com/mackayj/WebApi.OutputCache.Redis.ServiceStack

https://github.com/mackayj/WebApi.OutputCache.Redis.StackExchange

回答

3

byte[]RedisValue之间的转换使用一个conversion operator。该值只是编译器已知的object,但它不知道它需要调用转换运算符。即如果你写了下面的代码:

object result = someRedisValue; 
byte[] bytes = (byte[])result; 

编译器写入类似最后一行,它失败了以下内容:

cast result to byte[] // runtime error: it's not a byte[]! 
store that in 'bytes' 

你可以让编译器解决了这个认识真正类型尝试对其进行转换之前的对象。

byte[] bytes = (RedisValue)result; 

这将导致编译器来写这样的代码:

cast result to RedisValue 
call RedisValue's implicit RedisValue to byte[] conversion on that 
store that in 'bytes' 
+0

问题是接口正在返回一个对象,调用代码正在做一个'as byte []'。我试图不修改接口或主代码,但我想我现在只是添加一个返回字节[]的新方法。我编辑我的帖子,显示正确的调用代码与'作为字节[]' – John 2014-10-03 17:43:40

2

这是一个有趣的问题。还有我能想到接近它的几种方法:

  • 其转换为byte[]存放
之前将其存储
  • 作弊与dynamic
  • 敷在一些其他可识别包装前

    本质上,自定义转换运算符在拆箱时不起作用,除非您使用dynamic

    我也可以实现IConvertible或其他一些众所周知的界面。

  • +0

    我越想到它,我更确定''RedisValue'应该':IConvertible'。这可能会在下一个下降。 – 2014-10-03 18:04:25

    +0

    感谢您的快速回复Marc!我用一个直接调用代替了那个代码,它返回的是byte []而不是object,并且注意到它在多个其他地方('as string'和'MediaTypeHeaderValue'调用)实际上失败了。我试着把它设置为一个'dynamic result = _database.GetString(key)',但是它给出了相同的结果,你用动态作弊是什么意思?有没有办法让它返回一个对象,而不是将其转换为RedisValue? – John 2014-10-03 18:20:08

    +0

    我最终只是为'ServiceStack.Redis'切换了'StackExchange.Redis',并且我能够毫无问题地做到这一点。我非常喜欢你的版本,因为它更小。如果有一种方法只是使用'object'而不是'RedisValue'作为返回类型,请让我知道,所以我可以将它交换回来:) – John 2014-10-03 19:32:13

    1

    下面的代码使用StackExchange.Redis可以设置/获取泛型类型的值并在进程中将RedisValue转换为byte [],它对于任何可序列化类型都应该可以正常工作。

    public static void SetItem<T>(string key, T value) 
        { 
    
         IDatabase redDb = GetDB(); 
         redDb.StringSet(key, ToByteArray<T>(value)); 
        } 
    
        public static T GetItem<T>(string key) 
        { 
         IDatabase redDb = GetDB(); 
         RedisValue redisResult = redDb.StringGet(key); 
         T objResult = FromByteArray<T>(redisResult); 
         return objResult; 
        } 
    
        public static byte[] ToByteArray<T>(T obj) 
        { 
         if (obj == null) 
          return null; 
         BinaryFormatter bf = new BinaryFormatter(); 
         using (MemoryStream ms = new MemoryStream()) 
         { 
          bf.Serialize(ms, obj); 
          return ms.ToArray(); 
         } 
        } 
    
        public static T FromByteArray<T>(byte[] data) 
        { 
         if (data == null) 
          return default(T); 
         BinaryFormatter bf = new BinaryFormatter(); 
         using (MemoryStream ms = new MemoryStream(data)) 
         { 
          object obj = bf.Deserialize(ms); 
          return (T)obj; 
         } 
        }