Esempio n. 1
0
        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()
            });
        }