2014-10-03 4 views
5

Я пытаюсь создать поставщика Redis для Strathweb.CacheOutput.WebApi2, но пытается конвертировать из байта [] -> RedisValue - > byte [] возвращает null.StackExchange.Redis casting RedisValue to byte [] через «as byte []» возвращает null

Я могу вручную задать тип объекта как byte [] вместо var/RedisValue, и он будет правильно возвращать значение в виде байта [], но после того, как он был установлен как 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; 

Edit: Добавление примеров API я реализован с использованием как ServiceStack.Redis v3 (рабочее атм в нем просто использует 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

Проблема заключается в том, что интерфейс возвращает объект, а вызывающий код выполняет 'как byte []'. Я пытаюсь не изменять интерфейс или основной код для него, но я думаю, что я просто добавлю новый метод, который возвращает байт []. Я отредактировал свой пост, чтобы показать правильный код вызова с 'as byte []' – John

2

Это интересная проблема.Есть несколько способов, которыми я могу думать о приближении к ней:

  • приводите его к byte[] перед хранением
  • обманщик с dynamic
  • обернуть его в какой-либо другой идентифицирующей обертке перед сохранением его

По сути, пользовательские операторы преобразования не работают при распаковке, если вы не используете dynamic

Я также мог бы реализовать IConvertible или какой-либо другой известный интерфейс.

+0

Чем больше я думаю об этом, тем увереннее, что я '' RedisValue' должен ': IConvertible'. Вероятно, это будет в следующем падении. –

+0

Спасибо за быстрый ответ Марк! Я заменил этот код на прямой вызов, который возвращает байт [] вместо объекта и замечает, что он фактически не работает в нескольких других местах (вызовы 'as string' и' as MediaTypeHeaderValue'). Я попробовал просто установить его как «динамический результат = _database.GetString (key)», но это дало тот же результат, что вы имели в виду, обманывая его динамическим? Есть ли способ просто вернуть объект вместо преобразования его в RedisValue? – John

+0

В итоге я просто отключил 'StackExchange.Redis' для' ServiceStack.Redis', и я смог сделать это без проблем. Мне очень нравится ваша версия, так как она намного меньше. Если есть способ просто использовать 'object', а не' RedisValue' в качестве возвращаемого типа, пожалуйста, дайте мне знать, чтобы я мог поменять его обратно :) – John

1

Следующий код с использованием StackExchange.Redis может установить/получить значение родового типа и преобразовать RedisValue в байт [] в процессе, он должен работать нормально для любого сериализуемого типа.

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

 Смежные вопросы

  • Нет связанных вопросов^_^