10

我正在尝试为 Strathweb.CacheOutput.WebApi2 创建一个 Redis 提供程序,但尝试从 byte[] -> RedisValue -> byte[] 转换返回 null。

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

他的接口有 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;

编辑:添加我使用 ServiceStack.Redis v3 实现的 API 示例(它只是使用的工作 atmobject和不工作的 StackExchange.Redis)

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

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

4

3 回答 3

5

以下使用 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;
        }
    }
于 2016-10-15T14:28:20.923 回答
4

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

  • byte[]在存储之前将其转换为
  • 欺骗dynamic
  • 在存储之前将其包装在其他可识别的包装中

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

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

于 2014-10-03T18:01:36.857 回答
4

byte[]和之间的转换RedisValue使用转换运算符。但是,编译器只知道该值是一个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'
于 2014-10-03T17:30:18.987 回答