在StackExchange.Redis中将对象转换为HashEntry

时间:2014-08-12 12:07:28

标签: c# .net redis stackexchange.redis

我想在redis中使用HashSet使用StackExchange.Redis,但在db.HashSet()中我应该传递HashEntry类型,如何将对象转换为HashEntry,我知道反射,是否有转换对象的快速代码?

3 个答案:

答案 0 :(得分:5)

我知道这已经超过 6 年了,但是当我搜索时,互联网上的信息仍然太多。所以我决定写在这里,如果有人需要的话。

下面有两种方法。 ToHashEntries 用于将对象写入 redis,ConvertFromRedis 用于从 redis 读取对象。

注意:我使用 Newtonsoft.Json 库作为 json 转换器。

    public static HashEntry[] ToHashEntries(object obj)
    {
        PropertyInfo[] properties = obj.GetType().GetProperties();
        return properties
            .Where(x => x.GetValue(obj) != null) // <-- PREVENT NullReferenceException
            .Select
            (
                  property =>
                  {
                      object propertyValue = property.GetValue(obj);
                      string hashValue;

                      // This will detect if given property value is 
                      // enumerable, which is a good reason to serialize it
                      // as JSON!
                      if (propertyValue is IEnumerable<object>)
                      {
                          // So you use JSON.NET to serialize the property
                          // value as JSON
                          hashValue = JsonConvert.SerializeObject(propertyValue);
                      }
                      else
                      {
                          hashValue = propertyValue.ToString();
                      }

                      return new HashEntry(property.Name, hashValue);
                  }
            )
            .ToArray();
    }

    public static T ConvertFromRedis<T>(HashEntry[] hashEntries)
    {
        PropertyInfo[] properties = typeof(T).GetProperties();
        var obj = Activator.CreateInstance(typeof(T));
        foreach (var property in properties)
        {
            HashEntry entry = hashEntries.FirstOrDefault(g => g.Name.ToString().Equals(property.Name));
            if (entry.Equals(new HashEntry())) continue;
            property.SetValue(obj, Convert.ChangeType(entry.Value.ToString(), property.PropertyType));
        }
        return (T)obj;
    }

用法:

public class RedisContext
{
    private static RedisContext _redisContext;
    private static IDatabase _redis;

    private RedisContext()
    {
        _redis = ConnectionMultiplexer.Connect(Utils.REDIS_HOST).GetDatabase();
    }

    public static RedisContext GetInstance()
    {
        if (_redisContext == null)
            _redisContext = new RedisContext();
        return _redisContext;
    }

    public void set<T>(string key, T obj)
    {
        if (typeof(T) == typeof(string))
            _redis.StringSet(key, obj.ToString());
        else
            _redis.HashSet(key, RedisConverter.ToHashEntries(obj));
    }

    public T get<T>(string key)
    {
        if (typeof(T) == typeof(string))
            return (T)Convert.ChangeType(_redis.StringGet(key), typeof(T));
        else
            return RedisConverter.ConvertFromRedis<T>(_redis.HashGetAll(key));
    }
}

答案 1 :(得分:3)

该库当前不包含用于将哈希映射到对象和相关属性的任何层。如果你想要它,你必须单独做,可能使用像反射这样的东西,但也许使用像FastMember或HyperDescriptor这样的辅助工具。

答案 2 :(得分:2)

扩展 Kadir Kalkan 的 answer,如果 HashEntry 包含枚举,这里是解决方案。

将第 property.SetValue(obj, Convert.ChangeType(entry.Value.ToString(), property.PropertyType)); 行替换为:

            object? propValue;
            if (property.PropertyType.IsEnum)
            {
                propValue = Enum.Parse(property.PropertyType, entry.Value.ToString(), true);
            }
            else
            {
                propValue = Convert.ChangeType(entry.Value.ToString(), property.PropertyType);
            }

            property.SetValue(obj, propValue);