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); } }