public override async Task WriteAsync(RedisConvert convert, Type objectType, object value, Namespace name, TimeSpan?TTL = null) { //Prepare the options RedisOptionAttribute options = objectType.GetCustomAttribute <RedisOptionAttribute>(); if (options == null) { options = new RedisOptionAttribute(); } //Store it as a simple string if (options.SingleValueKey) { await convert.Client.StoreStringAsync(name.Build(), value.ToString(), TTL); return; } //The content that will be written to the HashMap in bulk Dictionary <string, string> hashmap = new Dictionary <string, string>(); //Iterate over every property foreach (var property in objectType.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) { var ignoreAttribute = property.GetCustomAttribute <RedisIgnoreAttribute>(); if (ignoreAttribute != null) { continue; } //Prepare some property values var propertyName = property.Name; var propertyAttribute = property.GetCustomAttribute <RedisPropertyAttribute>(); if (propertyAttribute != null) { propertyName = propertyAttribute.DisplayName ?? property.Name; } //Prepare the serializer var serializer = convert.GetSerializerForType(property.PropertyType, property: propertyAttribute); Debug.Assert(serializer != null); //Push the name and then serialize it name.Push(propertyName); convert.SetHashMapBuffer(hashmap); await serializer.WriteAsync(convert, property.PropertyType, property.GetValue(value), name, TTL); name.Pop(); } //Flush our buffer convert.SetHashMapBuffer(hashmap); await convert.FlushHashMapAsync(name, TTL); }
/// <summary> /// Serializes a object into a single dictionary /// </summary> /// <param name="buffer">The dictionary that all the keys will be inserted into</param> /// <param name="obj">The object to parse</param> /// <param name="subkey">The current subkey</param> public static void Serialize(Dictionary <string, string> buffer, object obj, string subkey = "") { //Prepare the type and initial options Type type = obj.GetType(); //See if we should override the options RedisOptionAttribute options = type.GetCustomAttribute <RedisOptionAttribute>(); //Iterate over every property foreach (var property in type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) { SerializeMember(buffer, new SerializeMember(property), obj, subkey); } //Iterate over every field foreach (var field in type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) { SerializeMember(buffer, new SerializeMember(field), obj, subkey); } }
/// <summary> /// Gets the serializer for the given type. /// </summary> /// <param name="type"></param> /// <param name="options"></param> /// <param name="property"></param> /// <returns></returns> public RedisSerializer GetSerializerForType(Type type, RedisOptionAttribute options = null, RedisPropertyAttribute property = null) { if (options != null && options.Serializer != null) { return((RedisSerializer)Activator.CreateInstance(options.Serializer)); } if (property != null && property.Serializer != null) { return((RedisSerializer)Activator.CreateInstance(property.Serializer)); } if (type.IsPrimitive || type.IsEnum || type == typeof(string)) { return(new PrimitiveSerializer()); } if (type.IsGenericType) { if (type.GetGenericTypeDefinition() == typeof(Dictionary <,>)) { return(new DictionarySerializer()); } if (type.GetGenericTypeDefinition() == typeof(HashSet <>)) { return(new HashSetSerializer()); } if (type.GetGenericTypeDefinition() == typeof(List <>)) { return(new ListSerializer()); } } return(new ClassSerializer()); }
/// <summary> /// Deserializes a dictionary into a object /// </summary> /// <param name="buffer">The data that was received by the redis</param> /// <param name="type">The type of target object</param> /// <param name="reference">The target object</param> /// <param name="subkey">The subkey (optional)</param> /// <returns></returns> private static bool Deserialize(Dictionary <string, string> buffer, Type type, ref object reference, string subkey = "") { Debug.Assert(type != null); Debug.Assert(reference != null); Debug.Assert(buffer != null); //Prepare the type and initial options bool hasElements = false; //See if we should override the options RedisOptionAttribute options = type.GetCustomAttribute <RedisOptionAttribute>(); if (options == null) { options = new RedisOptionAttribute(); } //Create a new instance of the type foreach (var property in type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) { if (DeserializeMember(buffer, type, new SerializeMember(property), ref reference, subkey, options)) { hasElements = true; } } foreach (var field in type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) { if (DeserializeMember(buffer, type, new SerializeMember(field), ref reference, subkey, options)) { hasElements = true; } } //Return the element state return(hasElements); }
private static bool DeserializeMember(Dictionary <string, string> buffer, Type type, SerializeMember member, ref object reference, string subkey, RedisOptionAttribute options) { //Ignore elements with ignore attributes var ignoreAttribute = member.GetCustomAttribute <RedisIgnoreAttribute>(); if (ignoreAttribute != null) { return(false); } //Ignore generated blocks var generatedAttribute = member.GetCustomAttribute <System.Runtime.CompilerServices.CompilerGeneratedAttribute>(); if (generatedAttribute != null) { return(false); } //Serialize the member if it has an attribute or is forced to serialize. var attribute = member.GetCustomAttribute <RedisPropertyAttribute>(); if (attribute == null) { if (member.IsField) { return(false); } attribute = new RedisPropertyAttribute(member.Name); } //Prepare its key string key = PrepareKey(attribute, member.Name, subkey); //If class, we have to do something completely different //If it has a serialize attribute, we want to construct its serializer //var serializerAttribute = member.GetCustomAttribute<RedisSerializerAttribute>(); //if (serializerAttribute != null) //{ // //They have a custom serializer, so lets construct its type // var constructor = serializerAttribute.Serializer.GetConstructor(new Type[0]); // if (constructor != null) // { // var serializer = constructor.Invoke(new object[0]) as RedisSerializer; // if (serializer != null) // { // object v = serializer.Deserialize(buffer, member, key); // member.SetValue(reference, v); // return true; // } // // throw new Exception("Bad Serialization on the custom serializer! Failed to cast into a RedisSerializer"); // } // // throw new Exception("Bad Serialization on the custom serializer! Failed to find a constructor with 0 elements"); //} //If the property is a string, just cast ez pz if (member.IsPrimitive || member.IsString || member.IsEnum) { string primval; if (buffer.TryGetValue(key, out primval)) { if (member.IsPrimitive || member.IsEnum) { object v = TypeDescriptor.GetConverter(member.Type).ConvertFromString(primval); member.SetValue(reference, v); } else { member.SetValue(reference, primval); } return(true); } return(false); } //We have to do it the classical way with a subkey //var propvalConstructor = propertyType.GetConstructor(new Type[0]); //object propval = propvalConstructor.Invoke(new object[0]); object propval = null; try { propval = Activator.CreateInstance(member.Type); } catch (Exception e) { Console.WriteLine("Exception while creating a instance!"); throw e; } //Serialize if (propval != null && Deserialize(buffer, member.Type, ref propval, key + ".")) { member.SetValue(reference, propval); return(true); } return(false); }