/// <summary> /// Gets the reader with a specified generic method. /// </summary> private static BinaryReflectiveReadAction GetReader0(FieldInfo field, MethodInfo method, bool raw, params Type[] genericArgs) { Debug.Assert(field != null); Debug.Assert(field.DeclaringType != null); // non-static if (genericArgs.Length == 0) { genericArgs = new[] { field.FieldType } } ; // Call Reader method var readerParam = Expression.Parameter(typeof(IBinaryReader)); var readMethod = method.MakeGenericMethod(genericArgs); Expression readExpr = raw ? Expression.Call(Expression.Call(readerParam, MthdGetRawReader), readMethod) : Expression.Call(readerParam, readMethod, Expression.Constant(BinaryUtils.CleanFieldName(field.Name))); if (readMethod.ReturnType != field.FieldType) { readExpr = Expression.Convert(readExpr, field.FieldType); } // Assign field value var targetParam = Expression.Parameter(typeof(object)); var targetParamConverted = Expression.Convert(targetParam, typeof(object)); var assignExpr = Expression.Call(DelegateConverter.GetWriteFieldMethod(field), targetParamConverted, readExpr); // Compile and return return(Expression.Lambda <BinaryReflectiveReadAction>(assignExpr, targetParam, readerParam).Compile()); } }
/// <summary> /// Gets the reader with a specified write action. /// </summary> private static BinaryReflectiveWriteAction GetWriter <T>(FieldInfo field, Expression <Action <string, IBinaryWriter, T> > write) { Debug.Assert(field != null); Debug.Assert(field.DeclaringType != null); // non-static Debug.Assert(write != null); // Get field value var targetParam = Expression.Parameter(typeof(object)); var targetParamConverted = Expression.Convert(targetParam, field.DeclaringType); Expression fldExpr = Expression.Field(targetParamConverted, field); if (field.FieldType != typeof(T)) { fldExpr = Expression.Convert(fldExpr, typeof(T)); } // Call Writer method var writerParam = Expression.Parameter(typeof(IBinaryWriter)); var fldNameParam = Expression.Constant(BinaryUtils.CleanFieldName(field.Name)); var writeExpr = Expression.Invoke(write, fldNameParam, writerParam, fldExpr); // Compile and return return(Expression.Lambda <BinaryReflectiveWriteAction>(writeExpr, targetParam, writerParam).Compile()); }
/// <summary> /// Gets the writer with a specified generic method. /// </summary> private static BinaryReflectiveWriteAction GetWriter0(FieldInfo field, MethodInfo method, bool raw, params Type[] genericArgs) { Debug.Assert(field != null); Debug.Assert(field.DeclaringType != null); // non-static Debug.Assert(method != null); if (genericArgs.Length == 0) { genericArgs = new[] { field.FieldType } } ; // Get field value var targetParam = Expression.Parameter(typeof(object)); var targetParamConverted = Expression.Convert(targetParam, field.DeclaringType); var fldExpr = Expression.Field(targetParamConverted, field); // Call Writer method var writerParam = Expression.Parameter(typeof(IBinaryWriter)); var writeMethod = method.MakeGenericMethod(genericArgs); var writeExpr = raw ? Expression.Call(Expression.Call(writerParam, MthdGetRawWriter), writeMethod, fldExpr) : Expression.Call(writerParam, writeMethod, Expression.Constant(BinaryUtils.CleanFieldName(field.Name)), fldExpr); // Compile and return return(Expression.Lambda <BinaryReflectiveWriteAction>(writeExpr, targetParam, writerParam).Compile()); }
/// <summary> /// Compare two FieldInfo instances. /// </summary> private static int Compare(FieldInfo info1, FieldInfo info2) { string name1 = BinaryUtils.CleanFieldName(info1.Name); string name2 = BinaryUtils.CleanFieldName(info2.Name); return(string.Compare(name1, name2, StringComparison.OrdinalIgnoreCase)); }
/// <summary> /// Gets the reader with a specified read action. /// </summary> private static BinaryReflectiveReadAction GetReader <T>(FieldInfo field, Expression <Func <string, IBinaryReader, T> > read) { Debug.Assert(field != null); Debug.Assert(field.DeclaringType != null); // non-static // Call Reader method var readerParam = Expression.Parameter(typeof(IBinaryReader)); var fldNameParam = Expression.Constant(BinaryUtils.CleanFieldName(field.Name)); Expression readExpr = Expression.Invoke(read, fldNameParam, readerParam); if (typeof(T) != field.FieldType) { readExpr = Expression.Convert(readExpr, field.FieldType); } // Assign field value var targetParam = Expression.Parameter(typeof(object)); var targetParamConverted = Expression.Convert(targetParam, field.DeclaringType); var assignExpr = Expression.Call(DelegateConverter.GetWriteFieldMethod(field), targetParamConverted, readExpr); // Compile and return return(Expression.Lambda <BinaryReflectiveReadAction>(assignExpr, targetParam, readerParam).Compile()); }
/// <summary>Register type.</summary> /// <param name="type">Type.</param> /// <param name="typeId">Type ID.</param> /// <param name="converter">Name converter.</param> /// <param name="idMapper">ID mapper.</param> internal BinaryReflectiveSerializerInternal Register(Type type, int typeId, IBinaryNameMapper converter, IBinaryIdMapper idMapper) { Debug.Assert(_wActions == null && _rActions == null); List <FieldInfo> fields = new List <FieldInfo>(); Type curType = type; while (curType != null) { foreach (FieldInfo field in curType.GetFields(Flags)) { if (!field.IsNotSerialized) { fields.Add(field); } } curType = curType.BaseType; } IDictionary <int, string> idMap = new Dictionary <int, string>(); foreach (FieldInfo field in fields) { string fieldName = BinaryUtils.CleanFieldName(field.Name); int fieldId = BinaryUtils.FieldId(typeId, fieldName, converter, idMapper); if (idMap.ContainsKey(fieldId)) { throw new BinaryObjectException("Conflicting field IDs [type=" + type.Name + ", field1=" + idMap[fieldId] + ", field2=" + fieldName + ", fieldId=" + fieldId + ']'); } idMap[fieldId] = fieldName; } fields.Sort(Compare); var wActions = new BinaryReflectiveWriteAction[fields.Count]; var rActions = new BinaryReflectiveReadAction[fields.Count]; for (int i = 0; i < fields.Count; i++) { BinaryReflectiveWriteAction writeAction; BinaryReflectiveReadAction readAction; BinaryReflectiveActions.GetTypeActions(fields[i], out writeAction, out readAction, _rawMode); wActions[i] = writeAction; rActions[i] = readAction; } return(new BinaryReflectiveSerializerInternal(wActions, rActions, _rawMode)); }
/// <summary> /// Register type. /// </summary> /// <param name="type">Type.</param> /// <param name="typeId">Type ID.</param> /// <param name="converter">Name converter.</param> /// <param name="idMapper">ID mapper.</param> /// <param name="forceTimestamp">Force timestamp serialization for DateTime fields..</param> /// <returns>Resulting serializer.</returns> internal BinaryReflectiveSerializerInternal Register(Type type, int typeId, IBinaryNameMapper converter, IBinaryIdMapper idMapper, bool forceTimestamp) { Debug.Assert(_wActions == null && _rActions == null); var fields = ReflectionUtils.GetAllFields(type).Where(x => !x.IsNotSerialized).ToList(); IDictionary <int, string> idMap = new Dictionary <int, string>(); foreach (FieldInfo field in fields) { string fieldName = BinaryUtils.CleanFieldName(field.Name); int fieldId = BinaryUtils.FieldId(typeId, fieldName, converter, idMapper); if (idMap.ContainsKey(fieldId)) { if (fieldName == idMap[fieldId]) { string baseClassName = field.DeclaringType != null ? field.DeclaringType.Name : null; throw new BinaryObjectException(string.Format( "{0} derives from {1} and hides field {2} from the base class. " + "Ignite can not serialize two fields with the same name.", type.Name, baseClassName, fieldName)); } throw new BinaryObjectException(string.Format( "Conflicting field IDs [type={0}, field1={1}, field2={2}, fieldId={3}])", type.Name, idMap[fieldId], fieldName, fieldId)); } idMap[fieldId] = fieldName; } fields.Sort(Compare); var wActions = new BinaryReflectiveWriteAction[fields.Count]; var rActions = new BinaryReflectiveReadAction[fields.Count]; for (int i = 0; i < fields.Count; i++) { BinaryReflectiveWriteAction writeAction; BinaryReflectiveReadAction readAction; BinaryReflectiveActions.GetTypeActions(fields[i], out writeAction, out readAction, _rawMode, forceTimestamp); wActions[i] = writeAction; rActions[i] = readAction; } var serDesc = SerializableTypeDescriptor.Get(type); return(new BinaryReflectiveSerializerInternal(wActions, rActions, _rawMode, serDesc)); }
/// <summary>Register type.</summary> /// <param name="type">Type.</param> /// <param name="typeId">Type ID.</param> /// <param name="converter">Name converter.</param> /// <param name="idMapper">ID mapper.</param> public void Register(Type type, int typeId, IBinaryNameMapper converter, IBinaryIdMapper idMapper) { if (type.GetInterface(typeof(IBinarizable).Name) != null) { return; } List <FieldInfo> fields = new List <FieldInfo>(); Type curType = type; while (curType != null) { foreach (FieldInfo field in curType.GetFields(Flags)) { if (!field.IsNotSerialized) { fields.Add(field); } } curType = curType.BaseType; } IDictionary <int, string> idMap = new Dictionary <int, string>(); foreach (FieldInfo field in fields) { string fieldName = BinaryUtils.CleanFieldName(field.Name); int fieldId = BinaryUtils.FieldId(typeId, fieldName, converter, idMapper); if (idMap.ContainsKey(fieldId)) { throw new BinaryObjectException("Conflicting field IDs [type=" + type.Name + ", field1=" + idMap[fieldId] + ", field2=" + fieldName + ", fieldId=" + fieldId + ']'); } idMap[fieldId] = fieldName; } fields.Sort(Compare); Descriptor desc = new Descriptor(fields); _types[type] = desc; }
/// <summary> /// Register type. /// </summary> /// <param name="type">Type.</param> /// <param name="typeId">Type ID.</param> /// <param name="converter">Name converter.</param> /// <param name="idMapper">ID mapper.</param> /// <param name="forceTimestamp">Force timestamp serialization for DateTime fields..</param> /// <returns>Resulting serializer.</returns> internal BinaryReflectiveSerializerInternal Register(Type type, int typeId, IBinaryNameMapper converter, IBinaryIdMapper idMapper, bool forceTimestamp) { Debug.Assert(_wActions == null && _rActions == null); var fields = ReflectionUtils.GetAllFields(type).Where(x => !x.IsNotSerialized).ToList(); IDictionary <int, string> idMap = new Dictionary <int, string>(); foreach (FieldInfo field in fields) { string fieldName = BinaryUtils.CleanFieldName(field.Name); int fieldId = BinaryUtils.FieldId(typeId, fieldName, converter, idMapper); if (idMap.ContainsKey(fieldId)) { throw new BinaryObjectException("Conflicting field IDs [type=" + type.Name + ", field1=" + idMap[fieldId] + ", field2=" + fieldName + ", fieldId=" + fieldId + ']'); } idMap[fieldId] = fieldName; } fields.Sort(Compare); var wActions = new BinaryReflectiveWriteAction[fields.Count]; var rActions = new BinaryReflectiveReadAction[fields.Count]; for (int i = 0; i < fields.Count; i++) { BinaryReflectiveWriteAction writeAction; BinaryReflectiveReadAction readAction; BinaryReflectiveActions.GetTypeActions(fields[i], out writeAction, out readAction, _rawMode, forceTimestamp); wActions[i] = writeAction; rActions[i] = readAction; } var serDesc = SerializableTypeDescriptor.Get(type); return(new BinaryReflectiveSerializerInternal(wActions, rActions, _rawMode, serDesc)); }
/// <summary> /// Determines whether specified field should be written as timestamp. /// </summary> private static bool IsTimestamp(FieldInfo field, bool forceTimestamp, bool raw) { if (forceTimestamp) { return(true); } Debug.Assert(field != null && field.DeclaringType != null); var fieldName = BinaryUtils.CleanFieldName(field.Name); object[] attrs = null; if (fieldName != field.Name) { // Backing field, check corresponding property var prop = field.DeclaringType.GetProperty(fieldName, field.FieldType); if (prop != null) { attrs = prop.GetCustomAttributes(true); } } attrs = attrs ?? field.GetCustomAttributes(true); if (attrs.Any(x => x is TimestampAttribute)) { return(true); } // Special case for DateTime and query fields. // If a field is marked with [QuerySqlField], write it as TimeStamp so that queries work. // This is not needed in raw mode (queries do not work anyway). // It may cause issues when field has attribute, but is used in a cache without queries, and user // may expect non-UTC dates to work. However, such cases are rare, and there are workarounds. return(!raw && attrs.Any(x => x is QuerySqlFieldAttribute)); }
/// <summary> /// Determines whether specified field is a query field (has QueryFieldAttribute). /// </summary> private static bool IsQueryField(FieldInfo fieldInfo) { Debug.Assert(fieldInfo != null && fieldInfo.DeclaringType != null); var fieldName = BinaryUtils.CleanFieldName(fieldInfo.Name); object[] attrs = null; if (fieldName != fieldInfo.Name) { // Backing field, check corresponding property var prop = fieldInfo.DeclaringType.GetProperty(fieldName, fieldInfo.FieldType); if (prop != null) { attrs = prop.GetCustomAttributes(true); } } attrs = attrs ?? fieldInfo.GetCustomAttributes(true); return(attrs.OfType <QuerySqlFieldAttribute>().Any()); }
/// <summary> /// Handle other type. /// </summary> /// <param name="field">The field.</param> /// <param name="writeAction">Write action.</param> /// <param name="readAction">Read action.</param> /// <param name="raw">Raw mode.</param> /// <param name="forceTimestamp">Force timestamp serialization for DateTime fields..</param> private static void HandleOther(FieldInfo field, out BinaryReflectiveWriteAction writeAction, out BinaryReflectiveReadAction readAction, bool raw, bool forceTimestamp) { var type = field.FieldType; var nullableType = Nullable.GetUnderlyingType(type); if (type == typeof(decimal)) { writeAction = raw ? GetRawWriter <decimal>(field, (w, o) => w.WriteDecimal(o)) : GetWriter <decimal>(field, (f, w, o) => w.WriteDecimal(f, o)); readAction = raw ? GetRawReader(field, r => r.ReadDecimal()) : GetReader(field, (f, r) => r.ReadDecimal(f)); } else if (type == typeof(string)) { writeAction = raw ? GetRawWriter <string>(field, (w, o) => w.WriteString(o)) : GetWriter <string>(field, (f, w, o) => w.WriteString(f, o)); readAction = raw ? GetRawReader(field, r => r.ReadString()) : GetReader(field, (f, r) => r.ReadString(f)); } else if (type == typeof(Guid)) { writeAction = raw ? GetRawWriter <Guid>(field, (w, o) => w.WriteGuid(o)) : GetWriter <Guid>(field, (f, w, o) => w.WriteGuid(f, o)); readAction = raw ? GetRawReader(field, r => r.ReadObject <Guid>()) : GetReader(field, (f, r) => r.ReadObject <Guid>(f)); } else if (nullableType == typeof(Guid)) { writeAction = raw ? GetRawWriter <Guid?>(field, (w, o) => w.WriteGuid(o)) : GetWriter <Guid?>(field, (f, w, o) => w.WriteGuid(f, o)); readAction = raw ? GetRawReader(field, r => r.ReadGuid()) : GetReader(field, (f, r) => r.ReadGuid(f)); } else if ((nullableType ?? type).IsEnum && !new[] { typeof(long), typeof(ulong) }.Contains(Enum.GetUnderlyingType(nullableType ?? type))) { writeAction = raw ? GetRawWriter <object>(field, (w, o) => w.WriteEnum(o)) : GetWriter <object>(field, (f, w, o) => w.WriteEnum(f, o)); readAction = raw ? GetRawReader(field, MthdReadEnumRaw) : GetReader(field, MthdReadEnum); } else if (type == typeof(IDictionary) || type == typeof(Hashtable)) { writeAction = raw ? GetRawWriter <IDictionary>(field, (w, o) => w.WriteDictionary(o)) : GetWriter <IDictionary>(field, (f, w, o) => w.WriteDictionary(f, o)); readAction = raw ? GetRawReader(field, r => r.ReadDictionary()) : GetReader(field, (f, r) => r.ReadDictionary(f)); } else if (type == typeof(ICollection) || type == typeof(ArrayList)) { writeAction = raw ? GetRawWriter <ICollection>(field, (w, o) => w.WriteCollection(o)) : GetWriter <ICollection>(field, (f, w, o) => w.WriteCollection(f, o)); readAction = raw ? GetRawReader(field, r => r.ReadCollection()) : GetReader(field, (f, r) => r.ReadCollection(f)); } else if (type == typeof(DateTime) && IsTimestamp(field, forceTimestamp, raw)) { writeAction = GetWriter <DateTime>(field, (f, w, o) => w.WriteTimestamp(f, o)); readAction = GetReader(field, (f, r) => r.ReadObject <DateTime>(f)); } else if (nullableType == typeof(DateTime) && IsTimestamp(field, forceTimestamp, raw)) { writeAction = GetWriter <DateTime?>(field, (f, w, o) => w.WriteTimestamp(f, o)); readAction = GetReader(field, (f, r) => r.ReadTimestamp(f)); } else if (type.IsPointer) { unsafe { // Expression trees do not work with pointers properly, use reflection. var fieldName = BinaryUtils.CleanFieldName(field.Name); writeAction = raw ? (BinaryReflectiveWriteAction)((o, w) => w.GetRawWriter().WriteLong((long)Pointer.Unbox(field.GetValue(o)))) : ((o, w) => w.WriteLong(fieldName, (long)Pointer.Unbox(field.GetValue(o)))); readAction = raw ? (BinaryReflectiveReadAction)((o, r) => field.SetValue(o, Pointer.Box((void *)r.GetRawReader().ReadLong(), field.FieldType))) : ((o, r) => field.SetValue(o, Pointer.Box((void *)r.ReadLong(fieldName), field.FieldType))); } } else { writeAction = raw ? GetRawWriter(field, MthdWriteObjRaw) : GetWriter(field, MthdWriteObj); readAction = raw ? GetRawReader(field, MthdReadObjRaw) : GetReader(field, MthdReadObj); } }