public static UnionSerializationInfo Create(Type type, Type resolverType, TypeBuilder typeBuilder, Microsoft.FSharp.Reflection.UnionCaseInfo caseInfo) { var ti = type.GetTypeInfo(); var members = new List <EmittableMember>(); foreach (var item in caseInfo.GetFields()) { var field = typeBuilder.DefineField("<>" + item.Name + item.Name + "Formatter", typeof(Formatter <,>).MakeGenericType(resolverType, item.PropertyType), FieldAttributes.Private | FieldAttributes.InitOnly); var member = new EmittableMember { PropertyInfo = item, Formatter = field }; members.Add(member); } MethodInfo method; var methodParameters = new List <EmittableMember>(); if (caseInfo.GetFields().Any()) { method = ti.GetMethod("New" + caseInfo.Name, BindingFlags.Static | BindingFlags.Public); } else { method = ti.GetProperty(caseInfo.Name, BindingFlags.Public | BindingFlags.Static).GetGetMethod(); } return(new UnionSerializationInfo { Tag = caseInfo.Tag, NewMethod = method, Members = members.ToArray() }); }
public static UnionSerializationInfo CreateOrNull(Type type, UnionCaseInfo caseInfo) { type = caseInfo.DeclaringType; var ti = type.GetTypeInfo(); var isClass = ti.IsClass; var contractAttr = ti.GetCustomAttribute <MessagePackObjectAttribute>(); var isIntKey = true; var intMembers = new Dictionary <int, EmittableMember>(); var stringMembers = new Dictionary <string, EmittableMember>(); if (contractAttr == null || contractAttr.KeyAsPropertyName) { isIntKey = false; var hiddenIntKey = 0; foreach (var item in caseInfo.GetFields()) { var member = new EmittableMember { PropertyInfo = item, StringKey = item.Name, IntKey = hiddenIntKey++ }; stringMembers.Add(member.StringKey, member); } } else { var hiddenIntKey = 0; foreach (var item in caseInfo.GetFields()) { var member = new EmittableMember { PropertyInfo = item, IntKey = hiddenIntKey++ }; intMembers.Add(member.IntKey, member); } } MethodInfo method; var methodParameters = new List <EmittableMember>(); if (caseInfo.GetFields().Any()) { method = ti.GetMethod("New" + caseInfo.Name, BindingFlags.Static | BindingFlags.Public); if (method == null) { throw new MessagePackDynamicUnionResolverException("can't find public method. case:" + caseInfo.Name); } var methodLookupDictionary = stringMembers.ToLookup(x => x.Key, x => x, StringComparer.OrdinalIgnoreCase); var methodParamIndex = 0; foreach (var item in method.GetParameters()) { EmittableMember paramMember; if (isIntKey) { if (intMembers.TryGetValue(methodParamIndex, out paramMember)) { if (item.ParameterType == paramMember.Type) { methodParameters.Add(paramMember); } else { throw new MessagePackDynamicUnionResolverException("can't find matched method parameter, parameterType mismatch. case:" + caseInfo.Name + " parameterIndex:" + methodParamIndex + " paramterType:" + item.ParameterType.Name); } } else { throw new MessagePackDynamicUnionResolverException("can't find matched method parameter, index not found. case:" + caseInfo.Name + " parameterIndex:" + methodParamIndex); } } else { var hasKey = methodLookupDictionary[item.Name]; var len = hasKey.Count(); if (len != 0) { if (len != 1) { throw new MessagePackDynamicUnionResolverException("duplicate matched method parameter name:" + caseInfo.Name + " parameterName:" + item.Name + " paramterType:" + item.ParameterType.Name); } paramMember = hasKey.First().Value; if (item.ParameterType == paramMember.Type) { methodParameters.Add(paramMember); } else { throw new MessagePackDynamicUnionResolverException("can't find matched method parameter, parameterType mismatch. case:" + caseInfo.Name + " parameterName:" + item.Name + " paramterType:" + item.ParameterType.Name); } } else { throw new MessagePackDynamicUnionResolverException("can't find matched method parameter, index not found. case:" + caseInfo.Name + " parameterName:" + item.Name); } } methodParamIndex++; } } else { method = ti.GetProperty(caseInfo.Name, BindingFlags.Public | BindingFlags.Static).GetGetMethod(); } return(new UnionSerializationInfo { IsClass = isClass, NewMethod = method, MethodParameters = methodParameters.ToArray(), IsIntKey = isIntKey, Members = (isIntKey) ? intMembers.Values.ToArray() : stringMembers.Values.ToArray() }); }
public static ObjectSerializationInfo CreateOrNull(Type type, bool forceStringKey) { var ti = type.GetTypeInfo(); var isClass = ti.IsClass; var contractAttr = ti.GetCustomAttribute <MessagePackObjectAttribute>(); if (contractAttr == null && !forceStringKey) { return(null); } var isIntKey = true; var intMemebrs = new Dictionary <int, EmittableMember>(); var stringMembers = new Dictionary <string, EmittableMember>(); if (forceStringKey || contractAttr.KeyAsPropertyName) { // All public members are serialize target except [Ignore] member. isIntKey = false; var hiddenIntKey = 0; foreach (var item in type.GetRuntimeProperties()) { if (item.GetCustomAttribute <IgnoreMemberAttribute>(true) != null) { continue; } var member = new EmittableMember { PropertyInfo = item, IsReadable = (item.GetGetMethod() != null) && item.GetGetMethod().IsPublic&& !item.GetGetMethod().IsStatic, IsWritable = (item.GetSetMethod() != null) && item.GetSetMethod().IsPublic&& !item.GetSetMethod().IsStatic, StringKey = item.Name }; if (!member.IsReadable && !member.IsWritable) { continue; } member.IntKey = hiddenIntKey++; stringMembers.Add(member.StringKey, member); } foreach (var item in type.GetRuntimeFields()) { if (item.GetCustomAttribute <IgnoreMemberAttribute>(true) != null) { continue; } if (item.GetCustomAttribute <System.Runtime.CompilerServices.CompilerGeneratedAttribute>(true) != null) { continue; } if (item.IsStatic) { continue; } var member = new EmittableMember { FieldInfo = item, IsReadable = item.IsPublic, IsWritable = item.IsPublic && !item.IsInitOnly, StringKey = item.Name }; if (!member.IsReadable && !member.IsWritable) { continue; } member.IntKey = hiddenIntKey++; stringMembers.Add(member.StringKey, member); } } else { // Public members with KeyAttribute except [Ignore] member. var searchFirst = true; var hiddenIntKey = 0; foreach (var item in type.GetRuntimeProperties()) { if (item.GetCustomAttribute <IgnoreMemberAttribute>(true) != null) { continue; } var member = new EmittableMember { PropertyInfo = item, IsReadable = (item.GetGetMethod() != null) && item.GetGetMethod().IsPublic&& !item.GetGetMethod().IsStatic, IsWritable = (item.GetSetMethod() != null) && item.GetSetMethod().IsPublic&& !item.GetSetMethod().IsStatic, }; if (!member.IsReadable && !member.IsWritable) { continue; } var key = item.GetCustomAttribute <KeyAttribute>(true); if (key == null) { throw new MessagePackDynamicObjectResolverException("all public members must mark KeyAttribute or IgnoreAttribute." + " type: " + type.FullName + " member:" + item.Name); } if (key.IntKey == null && key.StringKey == null) { throw new MessagePackDynamicObjectResolverException("both IntKey and StringKey are null." + " type: " + type.FullName + " member:" + item.Name); } if (searchFirst) { searchFirst = false; isIntKey = key.IntKey != null; } else { if ((isIntKey && key.IntKey == null) || (!isIntKey && key.StringKey == null)) { throw new MessagePackDynamicObjectResolverException("all members key type must be same." + " type: " + type.FullName + " member:" + item.Name); } } if (isIntKey) { member.IntKey = key.IntKey.Value; if (intMemebrs.ContainsKey(member.IntKey)) { throw new MessagePackDynamicObjectResolverException("key is duplicated, all members key must be unique." + " type: " + type.FullName + " member:" + item.Name); } intMemebrs.Add(member.IntKey, member); } else { member.StringKey = key.StringKey; if (stringMembers.ContainsKey(member.StringKey)) { throw new MessagePackDynamicObjectResolverException("key is duplicated, all members key must be unique." + " type: " + type.FullName + " member:" + item.Name); } member.IntKey = hiddenIntKey++; stringMembers.Add(member.StringKey, member); } } foreach (var item in type.GetRuntimeFields()) { if (item.GetCustomAttribute <IgnoreMemberAttribute>(true) != null) { continue; } if (item.GetCustomAttribute <System.Runtime.CompilerServices.CompilerGeneratedAttribute>(true) != null) { continue; } if (item.IsStatic) { continue; } var member = new EmittableMember { FieldInfo = item, IsReadable = item.IsPublic, IsWritable = item.IsPublic && !item.IsInitOnly, }; if (!member.IsReadable && !member.IsWritable) { continue; } var key = item.GetCustomAttribute <KeyAttribute>(true); if (key == null) { throw new MessagePackDynamicObjectResolverException("all public members must mark KeyAttribute or IgnoreAttribute." + " type: " + type.FullName + " member:" + item.Name); } if (key.IntKey == null && key.StringKey == null) { throw new MessagePackDynamicObjectResolverException("both IntKey and StringKey are null." + " type: " + type.FullName + " member:" + item.Name); } if (searchFirst) { searchFirst = false; isIntKey = key.IntKey != null; } else { if ((isIntKey && key.IntKey == null) || (!isIntKey && key.StringKey == null)) { throw new MessagePackDynamicObjectResolverException("all members key type must be same." + " type: " + type.FullName + " member:" + item.Name); } } if (isIntKey) { member.IntKey = key.IntKey.Value; if (intMemebrs.ContainsKey(member.IntKey)) { throw new MessagePackDynamicObjectResolverException("key is duplicated, all members key must be unique." + " type: " + type.FullName + " member:" + item.Name); } intMemebrs.Add(member.IntKey, member); } else { member.StringKey = key.StringKey; if (stringMembers.ContainsKey(member.StringKey)) { throw new MessagePackDynamicObjectResolverException("key is duplicated, all members key must be unique." + " type: " + type.FullName + " member:" + item.Name); } member.IntKey = hiddenIntKey++; stringMembers.Add(member.StringKey, member); } } } // GetConstructor var ctor = ti.DeclaredConstructors.Where(x => x.IsPublic).SingleOrDefault(x => x.GetCustomAttribute <SerializationConstructorAttribute>(false) != null); if (ctor == null) { ctor = ti.DeclaredConstructors.Where(x => x.IsPublic).OrderBy(x => x.GetParameters().Length).FirstOrDefault(); } // struct allows null ctor if (ctor == null && isClass) { throw new MessagePackDynamicObjectResolverException("can't find public constructor. type:" + type.FullName); } var constructorParameters = new List <EmittableMember>(); if (ctor != null) { var constructorLookupDictionary = stringMembers.ToLookup(x => x.Key, x => x, StringComparer.OrdinalIgnoreCase); var ctorParamIndex = 0; foreach (var item in ctor.GetParameters()) { EmittableMember paramMember; if (isIntKey) { if (intMemebrs.TryGetValue(ctorParamIndex, out paramMember)) { if (item.ParameterType == paramMember.Type && paramMember.IsReadable) { constructorParameters.Add(paramMember); } else { throw new MessagePackDynamicObjectResolverException("can't find matched constructor parameter, parameterType mismatch. type:" + type.FullName + " parameterIndex:" + ctorParamIndex + " paramterType:" + item.ParameterType.Name); } } else { throw new MessagePackDynamicObjectResolverException("can't find matched constructor parameter, index not found. type:" + type.FullName + " parameterIndex:" + ctorParamIndex); } } else { var hasKey = constructorLookupDictionary[item.Name]; var len = hasKey.Count(); if (len != 0) { if (len != 1) { throw new MessagePackDynamicObjectResolverException("duplicate matched constructor parameter name:" + type.FullName + " parameterName:" + item.Name + " paramterType:" + item.ParameterType.Name); } paramMember = hasKey.First().Value; if (item.ParameterType == paramMember.Type && paramMember.IsReadable) { constructorParameters.Add(paramMember); } else { throw new MessagePackDynamicObjectResolverException("can't find matched constructor parameter, parameterType mismatch. type:" + type.FullName + " parameterName:" + item.Name + " paramterType:" + item.ParameterType.Name); } } else { throw new MessagePackDynamicObjectResolverException("can't find matched constructor parameter, index not found. type:" + type.FullName + " parameterName:" + item.Name); } } ctorParamIndex++; } } return(new ObjectSerializationInfo { IsClass = isClass, BestmatchConstructor = ctor, ConstructorParameters = constructorParameters.ToArray(), IsIntKey = isIntKey, Members = (isIntKey) ? intMemebrs.Values.ToArray() : stringMembers.Values.ToArray() }); }