Esempio n. 1
0
        protected void VerifyParameterMapping(MethodBase methodBase)
        {
            var parameters = methodBase.GetParameters();

            if (parameters.Length == 0)
            {
                return;
            }

            var map = TypeConfig.ParameterMap ?? (TypeConfig.ParameterMap = new Dictionary <ParameterInfo, MemberInfo>());

            var memberConfigs = TypeConfig.Members.Where(mc => mc.ComputeFinalInclusionFast()).ToArray();

            foreach (var parameterInfo in parameters)
            {
                // Originally here was a lot of clever code here that tried to match by type, eliminate results, ...
                // but it turns out it's much better to simply let the user do stuff and throw errors as soon as there's just a hint of ambiguity!

                // Are we still missing a mapping for this member?
                if (!map.TryGetValue(parameterInfo, out MemberInfo sourceMember))
                {
                    var caseInsensitiveMatches = memberConfigs.Where(mc => parameterInfo.Name.Equals(mc.Member.Name, StringComparison.OrdinalIgnoreCase)).ToArray();
                    if (SetMatchOrThrow(parameterInfo, caseInsensitiveMatches))
                    {
                        continue;
                    }

                    var tolerantMatches = memberConfigs.Where(mc => parameterInfo.Name.Equals(MiscHelpers.CleanMemberName(mc.Member.Name), StringComparison.OrdinalIgnoreCase)).ToArray();
                    if (SetMatchOrThrow(parameterInfo, tolerantMatches))
                    {
                        continue;
                    }

                    var ctorParamStrings = string.Join(", ", parameters.Select(t => t.ParameterType.FriendlyName() + " " + t.Name));
                    throw new CerasException($"There is no mapping specified from the members of '{TypeConfig.Type.FriendlyName()}' to the constructor '({ctorParamStrings})'. Ceras has tried to automatically detect a mapping by matching the names of the fields/properties to the method parameters, but no source field or property could be found to populate the parameter '{parameterInfo.ParameterType.FriendlyName()} {parameterInfo.Name}'");
                }
                else
                {
                    // We already have a user-provided match, but is it part of the serialization?
                    var sourceMemberConfig = TypeConfig.Members.First(mc => mc.Member == sourceMember);
                    if (!sourceMemberConfig.ComputeFinalInclusionFast())
                    {
                        throw new CerasException($"The type construction mode for the type '{TypeConfig.Type.FriendlyName()}' is invalid because the parameter '{parameterInfo.ParameterType.FriendlyName()} {parameterInfo.Name}' is supposed to be initialized from the member '{sourceMember.FieldOrPropType().FriendlyName()} {sourceMember.Name}', but that member is not part of the serialization, so it will not be available at deserialization-time.");
                    }
                }
            }

            bool SetMatchOrThrow(ParameterInfo p, MemberConfig[] configs)
            {
                if (configs.Length > 1)
                {
                    throw new AmbiguousMatchException($"There are multiple members that match the parameter '{p.ParameterType.FriendlyName()} {p.Name}': {string.Join(", ", configs.Select(c => c.Member.Name))}");
                }

                if (configs.Length == 0)
                {
                    return(false);
                }

                map.Add(p, configs[0].Member);
                return(true);
            }
        }