public static CompareOption[] GetDefaultCompareOptions(Type type, Func <Type, MemberInfo, int> memberOrder = null) { if (DataType.IsPrimitiveType(type)) { return new CompareOption[] { GetDefaultCompareOption(type) } } ; if (type == typeof(Guid)) { return new CompareOption[] { GetDefaultCompareOption(type) } } ; if (type.IsClass() || type.IsStruct()) { return(DataTypeUtils.GetPublicMembers(type, memberOrder).Select(x => GetDefaultCompareOption(x.GetUnderlyingType())).ToArray()); } throw new NotSupportedException(type.ToString()); }
public static Expression CreateEqualsBody(Expression x, Expression y, CompareOption[] compareOptions, Func <Type, MemberInfo, int> membersOrder) { var type = x.Type; var exitPoint = Expression.Label(typeof(bool)); if (DataType.IsPrimitiveType(type) || type == typeof(Guid)) { return(EqualityComparerHelper.GetEqualsCommand(x, y, compareOptions[0], exitPoint, true)); } else { List <Expression> list = new List <Expression>(); int i = 0; int count = DataTypeUtils.GetPublicMembers(type, membersOrder).Count(); foreach (var member in DataTypeUtils.GetPublicMembers(type, membersOrder)) { list.Add(GetEqualsCommand(Expression.PropertyOrField(x, member.Name), Expression.PropertyOrField(y, member.Name), compareOptions[i++], exitPoint, i == count)); } return(Expression.Block(typeof(bool), list)); } }
public static Expression CreateComparerBody(List <Expression> expressions, List <ParameterExpression> parameters, Expression x, Expression y, CompareOption[] compareOptions, Func <Type, MemberInfo, int> membersOrder) { var exitPoint = Expression.Label(typeof(int)); List <Expression> list = new List <Expression>(); List <ParameterExpression> variables = new List <ParameterExpression>(); bool haveCmp = false; if (expressions != null) { foreach (var expression in expressions) { list.Add(expression); } } if (parameters != null) { foreach (var parameter in parameters) { variables.Add(parameter); } } if (DataType.IsPrimitiveType(x.Type) || x.Type == typeof(Guid)) { foreach (var command in GetCompareCommands(x, y, Expression.Variable(typeof(int)), exitPoint, x.Type, compareOptions[0], true)) { list.Add(command); } } else { int i = 0; var cmp = Expression.Variable(typeof(int)); foreach (var field in DataTypeUtils.GetPublicMembers(x.Type, membersOrder)) { if (!haveCmp && (field.GetUnderlyingType() == typeof(char) || field.GetUnderlyingType() == typeof(byte[]) || field.GetUnderlyingType() == typeof(Decimal) || field.GetUnderlyingType() == typeof(String))) { haveCmp = true; variables.Add(cmp); } foreach (var command in GetCompareCommands(Expression.PropertyOrField(x, field.Name), Expression.PropertyOrField(y, field.Name), cmp, exitPoint, field.GetUnderlyingType(), compareOptions[i++], i == DataTypeUtils.GetPublicMembers(x.Type, membersOrder).Count())) { list.Add(command); } } } return(Expression.Block(typeof(int), variables, list)); }
public static Expression BuildBody(Expression Value1, Expression Value2, Func <Type, MemberInfo, int> membersOrder1, Func <Type, MemberInfo, int> membersOrder2) { var type1 = Value1.Type; var type2 = Value2.Type; if (type1 == typeof(Guid) || type2 == typeof(Guid)) { return(Expression.Assign(Value1, type1 == typeof(Guid) ? Value2.Type == typeof(Guid) ? Value2 : Expression.New(type1.GetConstructor(new Type[] { typeof(byte[]) }), Value2) : Expression.Call(Value2, type2.GetMethod("ToByteArray")) )); } if (type1.IsEnum() || type2.IsEnum()) { return(Expression.Assign(Value1, Expression.Convert(Value2, type1))); } if (IsEqualsTypes(type1, type2)) { return(Expression.Assign(Value1, Value2)); } if (IsNumberType(type1) && IsNumberType(type2)) { return(Expression.Assign(Value1, Expression.Convert(Value2, type1))); } if (type1.IsKeyValuePair()) { var key = Expression.Variable(type1.GetGenericArgument(0)); var value = Expression.Variable(type1.GetGenericArgument(1)); return(Expression.Assign(Value1, Expression.New((typeof(KeyValuePair <,>).MakeGenericType(key.Type, value.Type)).GetConstructor(new Type[] { key.Type, value.Type }), Expression.Block(key.Type, new ParameterExpression[] { key }, BuildBody(key, Expression.PropertyOrField(Value2, type2.IsKeyValuePair() ? "Key" : DataTypeUtils.GetPublicMembers(Value2.Type, membersOrder2).First().Name), membersOrder1, membersOrder2), Expression.Label(Expression.Label(key.Type), key)), Expression.Block(value.Type, new ParameterExpression[] { value }, BuildBody(value, Expression.PropertyOrField(Value2, type2.IsKeyValuePair() ? "Value" : DataTypeUtils.GetPublicMembers(Value2.Type, membersOrder2).Last().Name), membersOrder1, membersOrder2), Expression.Label(Expression.Label(value.Type), value)) ))); } if (type1.IsList() || type1.IsArray) { var element = Expression.Variable(type1.IsArray ? type1.GetElementType() : type1.GetGenericArgument(0)); var block = Expression.Block(new ParameterExpression[] { element }, Expression.Assign(Value1, Expression.New(Value1.Type.GetConstructor(new Type[] { typeof(int) }), Expression.PropertyOrField(Value2, type2.IsList() ? "Count" : "Length"))), Value2.For(i => { return(type2.IsList() ? (Expression)Expression.Call(Value1, type1.GetMethod("Add"), BuildBody(element, Value2.This(i), membersOrder1, membersOrder2)) : Expression.Assign(Expression.ArrayAccess(Value1, i), BuildBody(element, Expression.ArrayAccess(Value2, i), membersOrder1, membersOrder2))); }, Expression.Label()) ); return(Expression.IfThenElse(Expression.NotEqual(Value2, Expression.Constant(null)), block, Expression.Assign(Value1, Expression.Constant(null, Value1.Type)))); } if (type1.IsDictionary()) { if (!DataType.IsPrimitiveType(type1.GetGenericArgument(0)) && type1.GetGenericArgument(0) == typeof(Guid)) { throw new NotSupportedException(String.Format("Dictionary<{0}, TValue>", type1.GetGenericArgument(0))); } var key = Expression.Variable(type1.GetGenericArgument(0)); var value = Expression.Variable(type1.GetGenericArgument(1)); var block = Expression.Block(new ParameterExpression[] { key, value }, Expression.Assign(Value1, type2.GetGenericArgument(0) == typeof(byte[]) ? Expression.New(type1.GetConstructor(new Type[] { typeof(int), typeof(IEqualityComparer <byte[]>) }), Expression.PropertyOrField(Value2, "Count"), Expression.Field(null, typeof(BigEndianByteArrayEqualityComparer), "Instance")) : Expression.New(type1.GetConstructor(new Type[] { typeof(int) }), Expression.PropertyOrField(Value2, "Count"))), Value2.ForEach(current => Expression.Call(Value1, type1.GetMethod("Add"), BuildBody(key, Expression.Property(current, "Key"), membersOrder1, membersOrder2), BuildBody(value, Expression.Property(current, "Value"), membersOrder1, membersOrder2)), Expression.Label() )); return(Expression.IfThenElse(Expression.NotEqual(Value2, Expression.Constant(null)), block, Expression.Assign(Value1, Expression.Constant(null, Value1.Type)))); } if (type1.IsNullable()) { var data1Var = Expression.Variable(Value1.Type); var data2Var = Expression.Variable(Value2.Type); List <Expression> list = new List <Expression>(); var constructParam = Expression.PropertyOrField(data2Var, type2.IsNullable() ? "Value" : DataTypeUtils.GetPublicMembers(type2, membersOrder2).First().Name); var block = Expression.Block(new ParameterExpression[] { data1Var, data2Var }, Expression.Assign(data2Var, Value2), Expression.Assign(data1Var, Expression.New( type1.GetConstructor(new Type[] { type1.GetGenericArgument(0) }), constructParam.GetType() == type1.GetGenericArgument(0) ? (Expression)constructParam : (Expression)Expression.Convert(constructParam, type1.GetGenericArgument(0)))), Expression.Assign(Value1, data1Var) ); return(Expression.IfThenElse(Expression.NotEqual(Value2, Expression.Constant(null, type2)), block, Expression.Assign(Value1, Expression.Constant(null, type1)) )); } if (type1.IsClass() || type1.IsStruct()) { var data1Var = Expression.Variable(Value1.Type); var data2Var = Expression.Variable(Value2.Type); List <Expression> list = new List <Expression>(); list.Add(Expression.Assign(data1Var, Expression.New(data1Var.Type))); List <MemberInfo> members1 = DataTypeUtils.GetPublicMembers(Value1.Type, membersOrder1).ToList(); List <MemberInfo> members2 = new List <MemberInfo>(); if (type2.IsKeyValuePair() || type2.IsNullable()) { if (type2.IsKeyValuePair()) { members2.Add(type2.GetMember("Key")[0]); } members2.Add(type2.GetMember("Value")[0]); } else { members2 = DataTypeUtils.GetPublicMembers(Value2.Type, membersOrder2).ToList(); } for (int i = 0; i < members1.Count; i++) { list.Add(BuildBody(Expression.PropertyOrField(data1Var, members1[i].Name), Expression.PropertyOrField(data2Var, members2[i].Name), membersOrder1, membersOrder2)); } list.Add(Expression.Assign(Value1, data1Var)); if ((type1.IsStruct() || type2.IsStruct()) && !type2.IsNullable()) { list.Insert(0, Expression.Assign(data2Var, Value2)); list.Add(Expression.Label(Expression.Label(Value1.Type), Value1)); return(Expression.Block(type1, new ParameterExpression[] { data1Var, data2Var }, list)); } return(Expression.Block(type1, new ParameterExpression[] { data2Var }, Expression.Assign(data2Var, Value2), Expression.IfThenElse(Expression.NotEqual(data2Var, Expression.Constant(null)), Expression.Block(new ParameterExpression[] { data1Var }, list), Expression.Assign(Value1, Expression.Constant(null, type1))), Expression.Label(Expression.Label(type1), Value1) )); } throw new NotSupportedException(type1.ToString()); }
public static bool CheckCompatible(Type type1, Type type2, HashSet <Type> cycleCheck, Func <Type, MemberInfo, int> membersOrder1 = null, Func <Type, MemberInfo, int> membersOrder2 = null) { if (type1 == typeof(Guid) || type1 == typeof(byte[])) { return(type2 == typeof(Guid) || type2 == typeof(byte[])); } if (type1.IsEnum() || type2.IsEnum()) { return((type1.IsEnum() && type2.IsEnum()) || (IsIntegerType(type1) || IsIntegerType(type2))); } if (DataType.IsPrimitiveType(type1)) { return((type1 == type2) || (IsNumberType(type1) && IsNumberType(type2))); } if (type1.IsArray) { return(CheckCompatible(type1.GetElementType(), type2.GetElementType(), cycleCheck, membersOrder1, membersOrder2)); } if (type1.IsList()) { return(CheckCompatible(type1.GetGenericArgument(0), type2.GetGenericArgument(0), cycleCheck, membersOrder1, membersOrder2)); } if (type1.IsDictionary()) { return(CheckCompatible(type1.GetGenericArgument(0), type2.GetGenericArgument(0), cycleCheck, membersOrder1, membersOrder2) && CheckCompatible(type1.GetGenericArgument(1), type2.GetGenericArgument(1), cycleCheck, membersOrder1, membersOrder2)); } if (type1.IsClass() || type1.IsStruct()) { List <Type> type1Slotes = new List <Type>(); List <Type> type2Slotes = new List <Type>(); if (type1.IsNullable()) { type1Slotes.Add(type1.GetGenericArgument(0)); } if (type2.IsNullable()) { type2Slotes.Add(type2.GetGenericArgument(0)); } if (type1.IsKeyValuePair()) { type1Slotes.Add(type1.GetGenericArgument(0)); type1Slotes.Add(type1.GetGenericArgument(1)); } if (type2.IsKeyValuePair()) { type2Slotes.Add(type2.GetGenericArgument(0)); type2Slotes.Add(type2.GetGenericArgument(1)); } foreach (var slote in DataTypeUtils.GetPublicMembers(type1, membersOrder1)) { type1Slotes.Add(slote.GetUnderlyingType()); } foreach (var slote in DataTypeUtils.GetPublicMembers(type2, membersOrder2)) { type2Slotes.Add(slote.GetUnderlyingType()); } if (type1Slotes.Count != type2Slotes.Count) { return(false); } for (int i = 0; i < type1Slotes.Count; i++) { if (cycleCheck.Contains(type1Slotes[i])) { throw new NotSupportedException(String.Format("Type {0} has cycle declaration.", type1Slotes[i])); } cycleCheck.Add(type1Slotes[i]); if (!CheckCompatible(type1Slotes[i], type2Slotes[i], cycleCheck, membersOrder1, membersOrder2)) { return(false); } cycleCheck.Remove(type1Slotes[i]); } return(true); } throw new NotSupportedException(type2.ToString()); }
public static Expression CreateParseBody(Expression item, ParameterExpression stringParam, IFormatProvider[] providers, char[] delimiters, Func <Type, MemberInfo, int> membersOrder) { var array = Expression.Variable(typeof(string[]), "array"); if (DataType.IsPrimitiveType(item.Type) || DataTypeUtils.GetPublicMembers(item.Type, membersOrder).Count() == 1) { var member = DataType.IsPrimitiveType(item.Type) ? item : Expression.PropertyOrField(item, DataTypeUtils.GetPublicMembers(item.Type, membersOrder).First().Name); Expression value; if (member.Type == typeof(String)) { value = stringParam; } else if (member.Type == typeof(byte[])) { var hexParse = typeof(StringExtensions).GetMethod("ParseHex", new Type[] { typeof(string) }); value = Expression.Call(hexParse, stringParam); } else if (member.Type == typeof(char)) { var parseMethod = member.Type.GetMethod("Parse", new Type[] { typeof(string) }); value = Expression.Call(parseMethod, stringParam); } else if (member.Type == typeof(bool)) { var parseMethod = member.Type.GetMethod("Parse"); value = Expression.Call(parseMethod, stringParam); } else { var parseMethod = member.Type.GetMethod("Parse", new Type[] { typeof(string), typeof(IFormatProvider) }); value = Expression.Call(parseMethod, stringParam, Expression.Constant(providers[0], typeof(IFormatProvider))); } return(Expression.Assign(member, value)); } List <Expression> list = new List <Expression>(); list.Add(Expression.Assign(array, Expression.Call(stringParam, typeof(string).GetMethod("Split", new Type[] { typeof(char[]) }), new Expression[] { Expression.Constant(delimiters) }))); int i = 0; foreach (var member in DataTypeUtils.GetPublicMembers(item.Type, membersOrder)) { list.Add(GetParseCommand(Expression.PropertyOrField(item, member.Name), i, array, providers[i++])); } return(Expression.Block(new ParameterExpression[] { array }, list)); }
public static Expression CreateToStringBody(Expression item, int stringBuilderCapacity, IFormatProvider[] providers, char delimiter, Func <Type, MemberInfo, int> membersOrder) { var stringBuilder = Expression.Variable(typeof(StringBuilder)); if (DataType.IsPrimitiveType(item.Type) || DataTypeUtils.GetPublicMembers(item.Type, membersOrder).Count() == 1) { var member = DataType.IsPrimitiveType(item.Type) ? item : Expression.PropertyOrField(item, DataTypeUtils.GetPublicMembers(item.Type, membersOrder).First().Name); MethodCallExpression callToString; if (member.Type == typeof(byte[])) { var toHexMethod = typeof(ByteArrayExtensions).GetMethod("ToHex", new Type[] { typeof(byte[]) }); callToString = Expression.Call(toHexMethod, member); } else if (member.Type == typeof(TimeSpan)) { var toStringProvider = member.Type.GetMethod("ToString", new Type[] { typeof(String), typeof(IFormatProvider) }); callToString = Expression.Call(member, toStringProvider, Expression.Constant(null, typeof(String)), Expression.Constant(providers[0], typeof(IFormatProvider))); } else { var toStringProvider = member.Type.GetMethod("ToString", new Type[] { typeof(IFormatProvider) }); callToString = Expression.Call(member, toStringProvider, Expression.Constant(providers[0], typeof(IFormatProvider))); } return(Expression.Label(Expression.Label(typeof(string)), member.Type == typeof(string) ? (Expression)member : (Expression)callToString)); } List <Expression> list = new List <Expression>(); list.Add(Expression.Assign(stringBuilder, Expression.New(stringBuilder.Type.GetConstructor(new Type[] { typeof(int) }), Expression.Constant(stringBuilderCapacity)))); int i = 0; foreach (var member in DataTypeUtils.GetPublicMembers(item.Type, membersOrder)) { list.Add(GetAppendCommand(Expression.PropertyOrField(item, member.Name), stringBuilder, providers[i])); if (i < DataTypeUtils.GetPublicMembers(item.Type, membersOrder).Count() - 1) { list.Add(Expression.Call(stringBuilder, typeof(StringBuilder).GetMethod("Append", new Type[] { typeof(char) }), Expression.Constant(delimiter))); } i++; } list.Add(Expression.Label(Expression.Label(typeof(string)), Expression.Call(stringBuilder, typeof(object).GetMethod("ToString")))); return(Expression.Block(new ParameterExpression[] { stringBuilder }, list)); }
private static Expression BuildRead(Expression reader, Type itemType, Func <Type, MemberInfo, int> membersOrder, AllowNull allowNull, int depth) { bool canBeNull = CanBeNull(itemType, allowNull, depth); if (itemType == typeof(Guid)) { return(Expression.New(itemType.GetConstructor(new Type[] { typeof(byte[]) }), GetReadCommand(reader, typeof(byte[]), canBeNull))); } if (itemType.IsEnum()) { return(Expression.Convert(GetReadCommand(reader, itemType.GetEnumBaseType(), canBeNull), itemType)); } if (DataType.IsPrimitiveType(itemType)) { return(GetReadCommand(reader, itemType, canBeNull)); } if (itemType.IsKeyValuePair()) { return(Expression.New( itemType.GetConstructor(new Type[] { itemType.GetGenericArgument(0), itemType.GetGenericArgument(1) }), BuildRead(reader, itemType.GetGenericArgument(0), membersOrder, allowNull, depth + 1), BuildRead(reader, itemType.GetGenericArgument(1), membersOrder, allowNull, depth + 1) )); } if (itemType.IsArray || itemType.IsList() || itemType.IsDictionary()) { var field = Expression.Variable(itemType); var lenght = Expression.Variable(typeof(int)); var block = Expression.Block( Expression.Assign(lenght, Expression.Convert(Expression.Call(typeof(CountCompression).GetMethod("Deserialize"), reader), typeof(int))), itemType.IsDictionary() && itemType.GetGenericArgument(0) == typeof(byte[]) ? Expression.Assign(field, Expression.New(field.Type.GetConstructor(new Type[] { typeof(int), typeof(IEqualityComparer <byte[]>) }), lenght, Expression.Field(null, typeof(BigEndianByteArrayEqualityComparer), "Instance"))) : Expression.Assign(field, Expression.New(field.Type.GetConstructor(new Type[] { typeof(int) }), lenght)), field.For(i => { if (itemType.IsArray) { return(Expression.Assign(Expression.ArrayAccess(field, i), BuildRead(reader, itemType.GetElementType(), membersOrder, allowNull, depth + 1))); } else if (itemType.IsList()) { return(Expression.Call(field, field.Type.GetMethod("Add"), BuildRead(reader, itemType.GetGenericArgument(0), membersOrder, allowNull, depth + 1))); } else //if (dataType.IsDictionary) { var keyType = itemType.GetGenericArgument(0); if (!IsSupportDictionaryKeyType(keyType)) { throw new NotSupportedException(String.Format("Dictionarty<{0}, TValue>", keyType.ToString())); } return(Expression.Call(field, field.Type.GetMethod("Add"), BuildRead(reader, itemType.GetGenericArgument(0), membersOrder, allowNull, depth + 1), BuildRead(reader, itemType.GetGenericArgument(1), membersOrder, allowNull, depth + 1) )); } }, Expression.Label(), lenght) ); if (canBeNull) { return(Expression.Block(field.Type, new ParameterExpression[] { field, lenght }, Expression.IfThenElse(Expression.Call(reader, typeof(BinaryReader).GetMethod("ReadBoolean")), block, Expression.Assign(field, Expression.Constant(null, field.Type))), Expression.Label(Expression.Label(field.Type), field))); } return(Expression.Block(field.Type, new ParameterExpression[] { field, lenght }, block, Expression.Label(Expression.Label(field.Type), field))); } if (itemType.IsNullable()) { if (!canBeNull) { return(Expression.New(itemType.GetConstructor(new Type[] { itemType.GetGenericArgument(0) }), BuildRead(reader, itemType.GetGenericArgument(0), membersOrder, allowNull, depth + 1))); } return(Expression.Condition(Expression.Call(reader, typeof(BinaryReader).GetMethod("ReadBoolean")), Expression.New(itemType.GetConstructor(new Type[] { itemType.GetGenericArgument(0) }), BuildRead(reader, itemType.GetGenericArgument(0), membersOrder, allowNull, depth + 1)), Expression.Constant(null, itemType))); } if (itemType.IsClass() || itemType.IsStruct()) { var item = Expression.Variable(itemType); List <Expression> list = new List <Expression>(); list.Add(Expression.Assign(item, Expression.New(item.Type))); foreach (var member in DataTypeUtils.GetPublicMembers(itemType, membersOrder)) { list.Add(Expression.Assign(Expression.PropertyOrField(item, member.Name), BuildRead(reader, member.GetUnderlyingType(), membersOrder, allowNull, depth + 1))); } if (!canBeNull) { list.Add(Expression.Label(Expression.Label(item.Type), item)); return(Expression.Block(item.Type, new ParameterExpression[] { item }, list)); } return(Expression.Block(itemType, new ParameterExpression[] { item }, Expression.IfThenElse(Expression.Call(reader, typeof(BinaryReader).GetMethod("ReadBoolean")), Expression.Block(list), Expression.Assign(item, Expression.Constant(null, itemType))), Expression.Label(Expression.Label(item.Type), item))); } throw new ArgumentException(itemType.ToString()); }
private static Expression BuildWrite(Expression item, Expression writer, Func <Type, MemberInfo, int> membersOrder, AllowNull allowNull, int depth) { var type = item.Type; bool canBeNull = CanBeNull(type, allowNull, depth); if (type == typeof(Guid)) { return(GetWriteCommand(writer, Expression.Call(item, type.GetMethod("ToByteArray")), canBeNull)); } if (type.IsEnum()) { return(GetWriteCommand(writer, Expression.Convert(item, item.Type.GetEnumBaseType()), canBeNull)); } if (DataType.IsPrimitiveType(type)) { return(GetWriteCommand(writer, item, canBeNull)); } if (type.IsKeyValuePair()) { return(Expression.Block( BuildWriteAssignedOrCurrent(Expression.PropertyOrField(item, "Key"), writer, membersOrder, allowNull, depth + 1), BuildWriteAssignedOrCurrent(Expression.PropertyOrField(item, "Value"), writer, membersOrder, allowNull, depth + 1) )); } if (type.IsArray || type.IsList()) { if (!canBeNull) { return(Expression.Block(Expression.Call(typeof(CountCompression).GetMethod("Serialize"), writer, Expression.Convert(type.IsArray ? (Expression)Expression.ArrayLength(item) : Expression.Property(item, "Count"), typeof(ulong))), item.For(i => BuildWriteAssignedOrCurrent(type.IsArray ? Expression.ArrayAccess(item, i) : item.This(i), writer, membersOrder, allowNull, depth + 1), Expression.Label()))); } return(Expression.IfThenElse(Expression.NotEqual(item, Expression.Constant(null)), Expression.Block( Expression.Call(writer, typeof(BinaryWriter).GetMethod("Write", new Type[] { typeof(bool) }), Expression.Constant(true)), Expression.Call(typeof(CountCompression).GetMethod("Serialize"), writer, Expression.Convert(type.IsArray ? (Expression)Expression.ArrayLength(item) : Expression.Property(item, "Count"), typeof(ulong))), item.For(i => BuildWriteAssignedOrCurrent(type.IsArray ? Expression.ArrayAccess(item, i) : item.This(i), writer, membersOrder, allowNull, depth + 1), Expression.Label())), Expression.Call(writer, typeof(BinaryWriter).GetMethod("Write", new Type[] { typeof(bool) }), Expression.Constant(false)) )); } if (type.IsDictionary()) { var keyType = type.GetGenericArgument(0); if (!IsSupportDictionaryKeyType(keyType)) { throw new NotSupportedException(String.Format("Dictionarty<{0}, TValue>", keyType.ToString())); } if (!canBeNull) { return(Expression.Block( Expression.Call(typeof(CountCompression).GetMethod("Serialize"), writer, Expression.Convert(Expression.Property(item, "Count"), typeof(ulong))), item.ForEach(current => { var kv = Expression.Variable(current.Type); return Expression.Block(new ParameterExpression[] { kv }, Expression.Assign(kv, current), BuildWriteAssignedOrCurrent(Expression.PropertyOrField(kv, "Key"), writer, membersOrder, allowNull, depth + 1), BuildWriteAssignedOrCurrent(Expression.PropertyOrField(kv, "Value"), writer, membersOrder, allowNull, depth + 1) ); }, Expression.Label()) )); } return(Expression.IfThenElse(Expression.NotEqual(item, Expression.Constant(null)), Expression.Block( Expression.Call(writer, typeof(BinaryWriter).GetMethod("Write", new Type[] { typeof(bool) }), Expression.Constant(true)), Expression.Call(typeof(CountCompression).GetMethod("Serialize"), writer, Expression.Convert(Expression.Property(item, "Count"), typeof(ulong))), item.ForEach(current => { var kv = Expression.Variable(current.Type); return Expression.Block(new ParameterExpression[] { kv }, Expression.Assign(kv, current), BuildWriteAssignedOrCurrent(Expression.PropertyOrField(kv, "Key"), writer, membersOrder, allowNull, depth + 1), BuildWriteAssignedOrCurrent(Expression.PropertyOrField(kv, "Value"), writer, membersOrder, allowNull, depth + 1) ); }, Expression.Label())), Expression.Call(writer, typeof(BinaryWriter).GetMethod("Write", new Type[] { typeof(bool) }), Expression.Constant(false)) )); } if (type.IsNullable()) { if (!canBeNull) { return(BuildWrite(Expression.PropertyOrField(item, "Value"), writer, membersOrder, allowNull, depth + 1)); } return(Expression.Block( Expression.Call(writer, typeof(BinaryWriter).GetMethod("Write", new Type[] { typeof(bool) }), Expression.PropertyOrField(item, "HasValue")), Expression.IfThen(Expression.PropertyOrField(item, "HasValue"), BuildWrite(Expression.PropertyOrField(item, "Value"), writer, membersOrder, allowNull, depth + 1)))); } if (type.IsClass() || type.IsStruct()) { List <ParameterExpression> variables = new List <ParameterExpression>(); List <Expression> list = new List <Expression>(); if (canBeNull) { list.Add(Expression.Call(writer, typeof(BinaryWriter).GetMethod("Write", new Type[] { typeof(bool) }), Expression.Constant(true))); } var members = DataTypeUtils.GetPublicMembers(type, membersOrder).ToList(); for (int i = 0; i < members.Count; i++) { var member = members[i]; var memberType = member.GetUnderlyingType(); if (DataType.IsPrimitiveType(memberType) || memberType.IsKeyValuePair()) { list.Add(BuildWrite(Expression.PropertyOrField(item, member.Name), writer, membersOrder, allowNull, depth + 1)); } else { var @var = Expression.Variable(member.GetUnderlyingType()); variables.Add(var); list.Add(Expression.Assign(var, Expression.PropertyOrField(item, member.Name))); list.Add(BuildWrite(var, writer, membersOrder, allowNull, depth + 1)); } } if (!canBeNull) { return(Expression.Block(variables, list)); } return(Expression.IfThenElse(Expression.NotEqual(item, Expression.Constant(null)), Expression.Block(variables, list), Expression.Call(writer, typeof(BinaryWriter).GetMethod("Write", new Type[] { typeof(bool) }), Expression.Constant(false)) )); } throw new NotSupportedException(item.Type.ToString()); }
public static Expression FromObjects(Expression item, ParameterExpression objectArray, Func <Type, MemberInfo, int> membersOrder) { Type[] types = DataType.IsPrimitiveType(item.Type) ? new Type[] { item.Type } : DataTypeUtils.GetPublicMembers(item.Type, membersOrder).Select(x => x.GetUnderlyingType()).ToArray(); if (types.Length == 1) { return(Expression.Assign(item, Expression.Convert(Expression.ArrayAccess(objectArray, Expression.Constant(0, typeof(int))), types[0]))); } List <Expression> list = new List <Expression>(); int i = 0; foreach (var member in DataTypeUtils.GetPublicMembers(item.Type, membersOrder)) { list.Add(Expression.Assign(Expression.PropertyOrField(item, member.Name), Expression.Convert(Expression.ArrayAccess(objectArray, Expression.Constant(i, typeof(int))), types[i++]))); } return(Expression.Block(list)); }
public static Expression ToObjects(Expression item, Func <Type, MemberInfo, int> membersOrder) { Type[] types = DataType.IsPrimitiveType(item.Type) ? new Type[] { item.Type } : DataTypeUtils.GetPublicMembers(item.Type, membersOrder).Select(x => x.GetUnderlyingType()).ToArray(); if (types.Length == 1) { return(Expression.NewArrayInit(typeof(object), Expression.Convert(item, typeof(object)))); } Expression[] values = new Expression[types.Length]; int i = 0; foreach (var member in DataTypeUtils.GetPublicMembers(item.Type, membersOrder)) { values[i++] = Expression.Convert(Expression.PropertyOrField(item, member.Name), typeof(object)); } return(Expression.NewArrayInit(typeof(object), values)); }
internal static Expression CreateStoreBody(Type type, IIndexerPersist[] persists, Expression writer, Expression callValues, ParameterExpression idx, Expression count, Func <Type, MemberInfo, int> membersOrder) { List <Expression> list = new List <Expression>(); int itemsCount = DataTypeUtils.GetPublicMembers(type, membersOrder).Count(); //Create body for single item. if (itemsCount <= 1) { var persist = Expression.Convert(Expression.Constant(persists[0]), persists[0].GetType()); var ms = Expression.Variable(typeof(MemoryStream), "ms"); var func = Expression.Lambda(itemsCount == 0 ? callValues : Expression.PropertyOrField(callValues, DataTypeUtils.GetPublicMembers(type, membersOrder).First().Name), idx); return(ms.Using(Expression.Block( Expression.Assign(ms, Expression.New(typeof(MemoryStream).GetConstructor(new Type[] { }))), Expression.Call(persist, persist.Type.GetMethod("Store"), Expression.New(typeof(BinaryWriter).GetConstructor(new Type[] { typeof(MemoryStream) }), ms), func, count), Expression.Call(typeof(CountCompression).GetMethod("Serialize"), writer, Expression.ConvertChecked(Expression.Property(ms, "Length"), typeof(ulong))), Expression.Call(writer, typeof(BinaryWriter).GetMethod("Write", new Type[] { typeof(byte[]), typeof(int), typeof(int) }), Expression.Call(ms, typeof(MemoryStream).GetMethod("GetBuffer")), Expression.Constant(0), Expression.Convert(Expression.Property(ms, "Length"), typeof(int))) ))); } else { var streams = Expression.Variable(typeof(MemoryStream[]), "streams"); var actions = Expression.Variable(typeof(Action[]), "actions"); list.Add(Expression.Assign(streams, Expression.New(typeof(MemoryStream[]).GetConstructor(new Type[] { typeof(int) }), Expression.Constant(itemsCount, typeof(int))))); list.Add(Expression.Assign(actions, Expression.New(typeof(Action[]).GetConstructor(new Type[] { typeof(int) }), Expression.Constant(itemsCount, typeof(int))))); int counter = 0; foreach (var member in DataTypeUtils.GetPublicMembers(type, membersOrder)) { var persist = Expression.Convert(Expression.Constant(persists[counter]), persists[counter].GetType()); var ms = Expression.ArrayAccess(streams, Expression.Constant(counter, typeof(int))); var func = Expression.Lambda(Expression.PropertyOrField(callValues, member.Name), idx); var writerNew = Expression.New(typeof(BinaryWriter).GetConstructor(new Type[] { typeof(MemoryStream) }), ms); var action = Expression.Lambda(Expression.Block( Expression.Assign(ms, Expression.New(typeof(MemoryStream).GetConstructor(new Type[] { }))), Expression.Call(persist, persist.Type.GetMethod("Store"), writerNew, func, count) )); list.Add(Expression.Assign(Expression.ArrayAccess(actions, Expression.Constant(counter)), action)); counter++; } list.Add(Expression.Call(typeof(Parallel).GetMethod("Invoke", new Type[] { typeof(Action[]) }), actions)); list.Add(streams.For( (i) => { var stream = Expression.Variable(typeof(MemoryStream), "stream"); return(stream.Using(Expression.Block( Expression.Assign(stream, Expression.ArrayAccess(streams, i)), Expression.Call(typeof(CountCompression).GetMethod("Serialize"), writer, Expression.ConvertChecked(Expression.Property(stream, "Length"), typeof(ulong))), Expression.Call(writer, typeof(BinaryWriter).GetMethod("Write", new Type[] { typeof(byte[]), typeof(int), typeof(int) }), Expression.Call(stream, typeof(MemoryStream).GetMethod("GetBuffer")), Expression.Constant(0), Expression.Convert(Expression.Property(stream, "Length"), typeof(int))) ))); }, Expression.Label() )); return(Expression.Block(new ParameterExpression[] { actions, streams }, list)); } }
private static Expression BuildGetSize(Expression item, int charSize, Func <Type, MemberInfo, int> membersOrder, AllowNull allowNull, int depth) { var type = item.Type; bool canBeNull = CanBeNull(type, allowNull, depth); if (type == typeof(Guid)) { return(GetPrimitiveValueSize(Expression.Call(item, type.GetMethod("ToByteArray")), charSize, false)); } if (type.IsEnum()) { return(GetPrimitiveValueSize(Expression.Convert(item, item.Type.GetEnumBaseType()), charSize, canBeNull)); } if (DataType.IsPrimitiveType(type)) { return(GetPrimitiveValueSize(item, charSize, canBeNull)); } if (type.IsKeyValuePair()) { var key = BuildGetSize(Expression.PropertyOrField(item, "Key"), charSize, membersOrder, allowNull, depth + 1); var value = BuildGetSize(Expression.PropertyOrField(item, "Value"), charSize, membersOrder, allowNull, depth + 1); return(Expression.Add(key, value)); } if (type.IsArray || type.IsList()) { var listSum = Expression.Variable(typeof(int)); var count = type.IsArray ? (Expression)Expression.ArrayLength(item) : Expression.Property(item, "Count"); var writeCount = Expression.Call(typeof(CountCompression).GetMethod("GetSize"), Expression.Convert(count, typeof(ulong))); int fixedSize = 0; var itemType = type.IsArray ? type.GetElementType() : type.GetGenericArgument(0); if (HasFixedSize(itemType, out fixedSize)) { if (!canBeNull) { return(Expression.Add(writeCount, Expression.Multiply(count, Expression.Constant(fixedSize)))); } return(Expression.Condition(Expression.NotEqual(item, Expression.Constant(null)), Expression.Add( Expression.Add(Expression.Constant(1), writeCount), Expression.Multiply(count, Expression.Constant(fixedSize))), Expression.Constant(1) )); } if (!canBeNull) { return(Expression.Block(new ParameterExpression[] { listSum }, Expression.Assign(listSum, writeCount), item.For(i => Expression.AddAssign(listSum, BuildGetSizeWithAssignedOrCurrentVariable(type.IsArray ? Expression.ArrayAccess(item, i) : item.This(i), charSize, membersOrder, allowNull, depth + 1)), Expression.Label()), Expression.Label(Expression.Label(typeof(int)), listSum) )); } return(Expression.Condition(Expression.NotEqual(item, Expression.Constant(null)), Expression.Block(new ParameterExpression[] { listSum }, Expression.Assign(listSum, Expression.Constant(1)), Expression.AddAssign(listSum, writeCount), item.For(i => Expression.AddAssign(listSum, BuildGetSizeWithAssignedOrCurrentVariable(type.IsArray ? Expression.ArrayAccess(item, i) : item.This(i), charSize, membersOrder, allowNull, depth + 1)), Expression.Label()), Expression.Label(Expression.Label(typeof(int)), listSum) ), Expression.Constant(1, typeof(int)) )); } if (type.IsDictionary()) { var keyType = type.GetGenericArgument(0); if (!IsSupportDictionaryKeyType(keyType)) { throw new NotSupportedException(String.Format("Dictionarty<{0}, TValue>", keyType.ToString())); } var valueType = type.GetGenericArgument(1); bool isEnum = type.GetGenericArgument(0).IsEnum(); if (!DataType.IsPrimitiveType(keyType) && !isEnum && type != typeof(Guid)) { throw new NotSupportedException(String.Format("Dictionarty<{0}, TValue>", type.GetGenericArgument(0).ToString())); } var dictSum = Expression.Variable(typeof(int)); var count = Expression.Property(item, "Count"); var writeCount = Expression.Call(typeof(CountCompression).GetMethod("GetSize"), Expression.Convert(count, typeof(ulong))); int keySize = 0; int valueSize = 0; if (HasFixedSize(keyType, out keySize) && HasFixedSize(valueType, out valueSize)) { if (!canBeNull) { return(Expression.Multiply(writeCount, Expression.Constant(keySize + valueSize))); } return(Expression.Condition(Expression.NotEqual(item, Expression.Constant(null)), Expression.Add( Expression.Constant(1), Expression.Multiply(writeCount, Expression.Constant(keySize + valueSize)) ), Expression.Constant(1) )); } if (!canBeNull) { return(Expression.Block(new ParameterExpression[] { dictSum }, Expression.Assign(dictSum, writeCount), item.ForEach(current => { var kv = Expression.Variable(current.Type); return Expression.Block(new ParameterExpression[] { kv }, Expression.Assign(kv, current), Expression.AddAssign(dictSum, BuildGetSizeWithAssignedOrCurrentVariable(Expression.PropertyOrField(kv, "Key"), charSize, membersOrder, allowNull, depth + 1)), Expression.AddAssign(dictSum, BuildGetSizeWithAssignedOrCurrentVariable(Expression.PropertyOrField(kv, "Value"), charSize, membersOrder, allowNull, depth + 1)) ); }, Expression.Label()), Expression.Label(Expression.Label(typeof(int)), dictSum) )); } return(Expression.Condition(Expression.NotEqual(item, Expression.Constant(null)), Expression.Block(new ParameterExpression[] { dictSum }, Expression.Assign(dictSum, Expression.Constant(1)), Expression.Assign(dictSum, writeCount), item.ForEach(current => { var kv = Expression.Variable(current.Type); return Expression.Block(new ParameterExpression[] { kv }, Expression.Assign(kv, current), Expression.AddAssign(dictSum, BuildGetSizeWithAssignedOrCurrentVariable(Expression.PropertyOrField(kv, "Key"), charSize, membersOrder, allowNull, depth + 1)), Expression.AddAssign(dictSum, BuildGetSizeWithAssignedOrCurrentVariable(Expression.PropertyOrField(kv, "Value"), charSize, membersOrder, allowNull, depth + 1)) ); }, Expression.Label()), Expression.Label(Expression.Label(typeof(int)), dictSum) ), Expression.Constant(1) )); } if (type.IsNullable()) { var getSize = BuildGetSize(Expression.PropertyOrField(item, "Value"), charSize, membersOrder, allowNull, depth + 1); if (!canBeNull) { return(getSize); } return(Expression.Condition(Expression.PropertyOrField(item, "HasValue"), Expression.Add(Expression.Constant(1), getSize), Expression.Constant(1) )); } if (type.IsClass() || type.IsStruct()) { List <ParameterExpression> variables = new List <ParameterExpression>(); List <Expression> list = new List <Expression>(); var members = DataTypeUtils.GetPublicMembers(type, membersOrder).ToList(); Expression megaAdd = Expression.Empty(); for (int i = 0; i < members.Count; i++) { var mType = members[i].GetUnderlyingType(); int mSize = 0; if (HasFixedSize(mType, out mSize)) { var getSize = BuildGetSize(Expression.PropertyOrField(item, members[i].Name), charSize, membersOrder, allowNull, depth + 1); megaAdd = (i == 0) ? getSize : Expression.Add(megaAdd, getSize); } else { var @var = Expression.Variable(members[i].GetUnderlyingType()); variables.Add(var); list.Add(Expression.Assign(var, Expression.PropertyOrField(item, members[i].Name))); var getSize = BuildGetSize(var, charSize, membersOrder, allowNull, depth + 1); megaAdd = (i == 0) ? getSize : Expression.Add(megaAdd, getSize); } } if (!canBeNull || type.IsStruct()) { if (list.Count == 0) { return(megaAdd); } list.Add(Expression.Label(Expression.Label(typeof(int)), megaAdd)); return(Expression.Block(variables, list)); } if (variables.Count == 0) { return(Expression.Block( Expression.Condition(Expression.NotEqual(item, Expression.Constant(null)), Expression.Add(Expression.Constant(1), megaAdd), Expression.Constant(1) ))); } list.Add(Expression.Label(Expression.Label(typeof(int)), Expression.Add(Expression.Constant(1), megaAdd))); return(Expression.Condition(Expression.NotEqual(item, Expression.Constant(null)), Expression.Block(variables, list), Expression.Constant(1) )); } throw new NotSupportedException(item.Type.ToString()); }