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

本文关键字:Redis 中的 HashEntry StackExchange 对象 转换 | 更新日期: 2023-09-27 18:17:32

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

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

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

下面有2个方法。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));
    }
}

库目前不包括任何映射哈希到/从对象和相关属性的层。如果你想这样做,你必须单独做,可能使用反射之类的东西,但也可能使用FastMember或HyperDescriptor之类的辅助工具。

扩展Kadir Kalkan的回答,如果HashEntry包含Enum,则解决方案如下。

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