StackExchange.Redis将RedisValue通过"as byte[]"转换为byte[]返回null

10
我正在尝试为Strathweb.CacheOutput.WebApi2创建一个Redis提供程序,但是将byte[] -> RedisValue -> byte[]进行转换时返回null。
我可以手动将对象类型设置为byte[]而不是var / RedisValue,这样它将正确地返回字节数组。但是,在将其设置为RedisValue之后,它无法将其转换为byte[]。
他的接口始终返回一个对象,因此我无法强制类型或使用单独的调用而不必修改接口。
如果我尝试执行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示例(目前正在工作,因为它只使用object),以及不起作用的StackExchange.Redis。

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

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

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

5

这是一个有趣的问题。我能想到几种方法来解决它:

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

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

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


我越想越确定RedisValue应该实现IConvertible接口。这可能会在下一个版本中实现。 - Marc Gravell
感谢您的快速回复,马克!我用直接调用替换了那段代码,它返回了byte[]而不是object,并且注意到它在其他多个地方也失败了(as stringas MediaTypeHeaderValue调用)。我尝试将其设置为dynamic result = _database.GetString(key),但结果相同,您所说的动态作弊是什么意思?有没有办法只返回一个对象而不是将其转换为RedisValue? - John
@John 关于你的“用动态方式欺骗它”的问题 - 就像这样](https://github.com/StackExchange/StackExchange.Redis/commit/d43495ce044aaceca9f2cd613b19bbc6b93dbec0);关于“返回对象而不是...RedisValue”的问题;不,因为RedisValue的整个重点是掩盖redis的“它是字符串?二进制大对象?计数器?”方面;当然,如果调用者之前将其转换为二进制大对象,则它可以是二进制大对象;您还可能想要[查看此提交](https://github.com/StackExchange/StackExchange.Redis/commit/ad04b0423ed180277993225d3973a2df45e60b94),它提供了对`IConvertible`的支持。 - Marc Gravell
1
@John,问题很简单:"object" 应该是什么? byte[]stringint? 如果你总是想要 byte[],那么在使用 "object" 之前 **只需将其转换为 byte[]**,即 RedisValue val = ...; object o = (byte[])val; // <=== use that - Marc Gravell
1
很不幸,该代码在多个位置被重复使用,一个用于获取ETag(字符串),一个用于获取数据(byte []),另一个用于获取标头(MediaTypeHeaderValue),因此我不能只是告诉它在返回之前始终将其转换为byte []。如果这三个调用从API中分开,那就会很容易了。 - John
显示剩余6条评论

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'

问题在于接口返回一个对象,而调用代码正在执行“as byte[]”。我试图不修改接口或主要代码,但我认为现在我只会添加一个新方法来返回byte[]。我编辑了我的帖子以显示正确的调用代码,使用“as byte[]”。 - John

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接