/// <summary> /// Adds an element with the provided property name and value to the <see cref="JsonObject"/>. /// </summary> /// <param name="propertyName">The property name of the element to add.</param> /// <param name="value">The value of the element to add.</param> /// <exception cref="ArgumentNullException"> /// <paramref name="propertyName"/>is <see langword="null"/>. /// </exception> /// <exception cref="ArgumentException"> /// An element with the same property name already exists in the <see cref="JsonObject"/>. /// </exception> public void Add(string propertyName, JsonNode?value) { InitializeIfRequired(); Debug.Assert(_dictionary != null); _dictionary.Add(propertyName, value); value?.AssignParent(this); }
private void InitializeIfRequired() { if (_dictionary != null) { return; } bool caseInsensitive = Options.HasValue ? Options.Value.PropertyNameCaseInsensitive : false; var dictionary = new JsonPropertyDictionary <JsonNode>(caseInsensitive); if (_jsonElement.HasValue) { JsonElement jElement = _jsonElement.Value; foreach (JsonProperty jElementProperty in jElement.EnumerateObject()) { JsonNode?node = JsonNodeConverter.Create(jElementProperty.Value, Options); if (node != null) { node.Parent = this; } dictionary.Add(new KeyValuePair <string, JsonNode?>(jElementProperty.Name, node)); } _jsonElement = null; } _dictionary = dictionary; }
internal void InitializeConstructorParameters(JsonParameterInfoValues[] jsonParameters, bool sourceGenMode = false) { var parameterCache = new JsonPropertyDictionary <JsonParameterInfo>(Options.PropertyNameCaseInsensitive, jsonParameters.Length); // Cache the lookup from object property name to JsonPropertyInfo using a case-insensitive comparer. // Case-insensitive is used to support both camel-cased parameter names and exact matches when C# // record types or anonymous types are used. // The property name key does not use [JsonPropertyName] or PropertyNamingPolicy since we only bind // the parameter name to the object property name and do not use the JSON version of the name here. var nameLookup = new Dictionary <ParameterLookupKey, ParameterLookupValue>(PropertyCache !.Count); foreach (KeyValuePair <string, JsonPropertyInfo?> kvp in PropertyCache.List) { JsonPropertyInfo jsonProperty = kvp.Value !; string propertyName = jsonProperty.ClrName !; ParameterLookupKey key = new(propertyName, jsonProperty.PropertyType); ParameterLookupValue value = new(jsonProperty); if (!JsonHelpers.TryAdd(nameLookup, key, value)) { // More than one property has the same case-insensitive name and Type. // Remember so we can throw a nice exception if this property is used as a parameter name. ParameterLookupValue existing = nameLookup[key]; existing.DuplicateName = propertyName; } } foreach (JsonParameterInfoValues parameterInfo in jsonParameters) { ParameterLookupKey paramToCheck = new(parameterInfo.Name, parameterInfo.ParameterType); if (nameLookup.TryGetValue(paramToCheck, out ParameterLookupValue? matchingEntry)) { if (matchingEntry.DuplicateName != null) { // Multiple object properties cannot bind to the same constructor parameter. ThrowHelper.ThrowInvalidOperationException_MultiplePropertiesBindToConstructorParameters( Type, parameterInfo.Name !, matchingEntry.JsonPropertyInfo.Name, matchingEntry.DuplicateName); } Debug.Assert(matchingEntry.JsonPropertyInfo != null); JsonPropertyInfo jsonPropertyInfo = matchingEntry.JsonPropertyInfo; JsonParameterInfo jsonParameterInfo = CreateConstructorParameter(parameterInfo, jsonPropertyInfo, sourceGenMode, Options); parameterCache.Add(jsonPropertyInfo.Name, jsonParameterInfo); } // It is invalid for the extension data property to bind with a constructor argument. else if (DataExtensionProperty != null && StringComparer.OrdinalIgnoreCase.Equals(paramToCheck.Name, DataExtensionProperty.Name)) { ThrowHelper.ThrowInvalidOperationException_ExtensionDataCannotBindToCtorParam(DataExtensionProperty); } } ParameterCount = jsonParameters.Length; Volatile.Write(ref ParameterCache, parameterCache); }