C# StackExchange.Redis通过“将RedisValue转换为字节[]”;作为字节[]”;返回空值
我正在尝试为Strathweb.CacheOutput.WebApi2创建Redis提供程序,但尝试从字节[]->RedisValue->byte[]转换时返回null 我可以手动将对象类型设置为byte[],而不是var/RedisValue,它将正确地将值返回为byte[],但在将其设置为RedisValue之后,它无法将其转换为byte[] 他的接口具有Get always返回对象的功能,因此我无法在不修改接口的情况下强制使用该类型或使用单独的调用 如果我尝试将C# StackExchange.Redis通过“将RedisValue转换为字节[]”;作为字节[]”;返回空值,c#,stackexchange.redis,C#,Stackexchange.redis,我正在尝试为Strathweb.CacheOutput.WebApi2创建Redis提供程序,但尝试从字节[]->RedisValue->byte[]转换时返回null 我可以手动将对象类型设置为byte[],而不是var/RedisValue,它将正确地将值返回为byte[],但在将其设置为RedisValue之后,它无法将其转换为byte[] 他的接口具有Get always返回对象的功能,因此我无法在不修改接口的情况下强制使用该类型或使用单独的调用 如果我尝试将结果作为字节[]执行,我会得
结果作为字节[]
执行,我会得到
无法通过引用转换、装箱转换、取消装箱转换、换行转换或空类型转换将类型“StackExchange.Redis.RedisValue”转换为“byte[]”
如果我尝试执行(byte[])结果
我得到无法将'result'(其实际类型为'StackExchange.Redis.RedisValue')强制转换为'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; }
}
}
编辑:添加我使用ServiceStack.Redis v3实现的API示例(atm工作,因为它只使用对象
和StackExchange.Redis,但不工作)
字节[]和值之间的转换使用。但是,编译器只知道该值是
对象
,因此它不知道需要调用转换运算符。即,如果您编写以下代码:
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'
这是一个有趣的问题。我可以想出几种方法来解决这个问题:
- 在存储之前将其强制转换为
字节[]
- 用
dynamic
- 在存储之前,将其包装在其他可识别的包装中
dynamic
我可能还可以实现
IConvertible
或其他一些著名的接口。下面的代码使用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;
}
}
publicstaticvoidsetitem(字符串键,T值)
{
IDatabase redDb=GetDB();
StringSet(key,ToByteArray(value));
}
公共静态T GetItem(字符串键)
{
IDatabase redDb=GetDB();
RedisValue redisResult=redDb.StringGet(键);
T objResult=FromByteArray(redisResult);
返回objResult;
}
公共静态字节[]ToByteArray(T obj)
{
if(obj==null)
返回null;
BinaryFormatter bf=新的BinaryFormatter();
使用(MemoryStream ms=new MemoryStream())
{
bf.序列化(ms,obj);
返回ToArray女士();
}
}
公共静态T FromByteArray(字节[]数据)
{
如果(数据==null)
返回默认值(T);
BinaryFormatter bf=新的BinaryFormatter();
使用(MemoryStream ms=新的MemoryStream(数据))
{
object obj=bf.反序列化(ms);
返回(T)obj;
}
}
问题是接口正在返回一个对象,而调用代码正在以字节[]的形式执行
。我试图不修改接口或它的主代码,但我想我现在要添加一个新方法,返回字节[]。我编辑了我的帖子,将正确的调用代码显示为byte[]我想得越多,就越确信RedisValue
应该:IConvertible
。这可能会在下一个下降。谢谢你的快速回复马克!我将该代码替换为直接调用,该调用返回byte[]而不是object,并注意到它实际上在多个其他地方也失败了(作为string
和作为MediaTypeHeaderValue
调用)。我尝试将其设置为动态结果=\u database.GetString(key)
,但结果相同,你用动态欺骗它是什么意思?有没有办法让它返回一个对象,而不是将其转换为RedisValue?我最终选择了StackExchange.Redis
作为ServiceStack.Redis
,这样我就可以毫无问题地完成它了。我真的更喜欢你的版本,因为它小得多。如果有一种方法只使用对象
而不是重贴现值
作为返回类型,请让我知道,这样我就可以将其调回:)@John,问题很简单:“对象
”应该是什么?字节[]
?字符串
?int
?如果您总是想要byte[]
,那么只需在object
之前强制转换到byte[]
,即RedisValue val=。。。;对象o=(字节[])val;//不幸的是,代码在多个位置被重复使用,一个用于获取etag(字符串),一个用于获取数据(字节[]),另一个用于获取标头(MediaTypeHeaderValue),所以我不能告诉它在返回之前总是转换成字节[]。我希望这是API的三个独立调用,因为这样做很容易。
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;
}
}