6

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

4

3 回答 3

6

我知道这已经 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));
    }
}
于 2021-03-23T08:33:36.160 回答
3

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

于 2014-08-12T14:33:05.647 回答
3

扩展 Kadir Kalkan 的答案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);
于 2021-04-22T22:01:30.843 回答