/// <summary> /// Gets the value associated with the specified property name. /// </summary> /// <param name="propertyName">The property name of the value to get.</param> /// <param name="jsonNode"> /// When this method returns, contains the value associated with the specified property name, if the property name is found; /// otherwise, <see langword="null"/>. /// </param> /// <returns> /// <see langword="true"/> if the <see cref="JsonObject"/> contains an element with the specified property name; otherwise, <see langword="false"/>. /// </returns> /// <exception cref="ArgumentNullException"> /// <paramref name="propertyName"/> is <see langword="null"/>. /// </exception> bool IDictionary <string, JsonNode?> .TryGetValue(string propertyName, out JsonNode?jsonNode) { InitializeIfRequired(); Debug.Assert(_dictionary != null); return(_dictionary.TryGetValue(propertyName, out jsonNode)); }
internal JsonParameterInfo?GetParameter( ReadOnlySpan <byte> propertyName, ref ReadStackFrame frame, out byte[] utf8PropertyName) { ParameterRef parameterRef; ulong key = GetKey(propertyName); // Keep a local copy of the cache in case it changes by another thread. ParameterRef[]? localParameterRefsSorted = _parameterRefsSorted; // If there is an existing cache, then use it. if (localParameterRefsSorted != null) { // Start with the current parameter index, and then go forwards\backwards. int parameterIndex = frame.CtorArgumentState !.ParameterIndex; int count = localParameterRefsSorted.Length; int iForward = Math.Min(parameterIndex, count); int iBackward = iForward - 1; while (true) { if (iForward < count) { parameterRef = localParameterRefsSorted[iForward]; if (IsParameterRefEqual(parameterRef, propertyName, key)) { utf8PropertyName = parameterRef.NameFromJson; return(parameterRef.Info); } ++iForward; if (iBackward >= 0) { parameterRef = localParameterRefsSorted[iBackward]; if (IsParameterRefEqual(parameterRef, propertyName, key)) { utf8PropertyName = parameterRef.NameFromJson; return(parameterRef.Info); } --iBackward; } } else if (iBackward >= 0) { parameterRef = localParameterRefsSorted[iBackward]; if (IsParameterRefEqual(parameterRef, propertyName, key)) { utf8PropertyName = parameterRef.NameFromJson; return(parameterRef.Info); } --iBackward; } else { // Property was not found. break; } } } // No cached item was found. Try the main dictionary which has all of the parameters. Debug.Assert(ParameterCache != null); if (ParameterCache.TryGetValue(JsonHelpers.Utf8GetString(propertyName), out JsonParameterInfo? info)) { Debug.Assert(info != null); if (Options.PropertyNameCaseInsensitive) { if (propertyName.SequenceEqual(info.NameAsUtf8Bytes)) { Debug.Assert(key == GetKey(info.NameAsUtf8Bytes.AsSpan())); // Use the existing byte[] reference instead of creating another one. utf8PropertyName = info.NameAsUtf8Bytes !; } else { // Make a copy of the original Span. utf8PropertyName = propertyName.ToArray(); } } else { Debug.Assert(key == GetKey(info.NameAsUtf8Bytes !.AsSpan())); utf8PropertyName = info.NameAsUtf8Bytes !; } } else { Debug.Assert(info == null); // Make a copy of the original Span. utf8PropertyName = propertyName.ToArray(); } // Check if we should add this to the cache. // Only cache up to a threshold length and then just use the dictionary when an item is not found in the cache. int cacheCount = 0; if (localParameterRefsSorted != null) { cacheCount = localParameterRefsSorted.Length; } // Do a quick check for the stable (after warm-up) case. if (cacheCount < ParameterNameCountCacheThreshold) { // Do a slower check for the warm-up case. if (frame.CtorArgumentState !.ParameterRefCache != null) { cacheCount += frame.CtorArgumentState.ParameterRefCache.Count; } // Check again to append the cache up to the threshold. if (cacheCount < ParameterNameCountCacheThreshold) { if (frame.CtorArgumentState.ParameterRefCache == null) { frame.CtorArgumentState.ParameterRefCache = new List <ParameterRef>(); } parameterRef = new ParameterRef(key, info !, utf8PropertyName); frame.CtorArgumentState.ParameterRefCache.Add(parameterRef); } } return(info); }