I want to make HashSet in redis use StackExchange.Redis,But in db.HashSet() I should pass HashEntry type , How I can convert object to HashEntry , I Know reflection ,Is there fast code for convert object?
I know it's been more than 6 years but when i search that still the information is too much distributed on internet. So i decide to write here if someone need it.
There are 2 method down below. ToHashEntries
for write object to redis and ConvertFromRedis
for read object from redis.
Note: I used Newtonsoft.Json
library as json converter.
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;
}
Usage:
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));
}
}
The library does not currently include any layer for mapping a hash to/from an object and related properties. If you want that, you would have to do that separately, perhaps using something like reflection, but perhaps using a helper tool like FastMember or HyperDescriptor.
Expanding on Kadir Kalkan's answer, here is the solution if the HashEntry
contains an Enum.
Replace line property.SetValue(obj, Convert.ChangeType(entry.Value.ToString(), property.PropertyType));
with:
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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With