internal static void WriteDictionary <TProperty>(
            JsonValueConverter <TProperty> converter,
            JsonSerializerOptions options,
            ref WriteStackFrame current,
            Utf8JsonWriter writer)
        {
            if (converter == null)
            {
                return;
            }

            Debug.Assert(current.Enumerator != null);

            string    key;
            TProperty value;

            if (current.Enumerator is IEnumerator <KeyValuePair <string, TProperty> > enumerator)
            {
                // Avoid boxing for strongly-typed enumerators such as returned from IDictionary<string, TRuntimeProperty>
                value = enumerator.Current.Value;
                key   = enumerator.Current.Key;
            }
            else
            {
                // Todo: support non-generic Dictionary here (IDictionaryEnumerator)
                throw new NotSupportedException();
            }

            if (value == null)
            {
                writer.WriteNull(key);
            }
            else
            {
#if true
                // temporary behavior until the writer can accept escaped string.
                byte[] utf8Key = Encoding.UTF8.GetBytes(key);
                converter.Write(utf8Key, value, writer);
#else
                byte[] pooledKey = null;
                byte[] utf8Key   = Encoding.UTF8.GetBytes(key);
                int    length    = JsonWriterHelper.GetMaxEscapedLength(utf8Key.Length, 0);

                Span <byte> escapedKey = length <= JsonConstants.StackallocThreshold ?
                                         stackalloc byte[length] :
                                         (pooledKey = ArrayPool <byte> .Shared.Rent(length));

                JsonWriterHelper.EscapeString(utf8Key, escapedKey, 0, out int written);

                converter.Write(escapedKey.Slice(0, written), value, writer);

                if (pooledKey != null)
                {
                    // We clear the array because it is "user data" (although a property name).
                    new Span <byte>(pooledKey, 0, written).Clear();
                    ArrayPool <byte> .Shared.Return(pooledKey);
                }
#endif
            }
        }
        private void AddProperty(Type propertyType, PropertyInfo propertyInfo, Type classType, JsonSerializerOptions options)
        {
            Type      collectionElementType = null;
            ClassType propertyClassType     = GetClassType(propertyType);

            if (propertyClassType == ClassType.Enumerable)
            {
                collectionElementType = GetElementType(propertyType);
                // todo: if collectionElementType is object, create loosely-typed collection (JsonArray).
            }

            // Create the JsonPropertyInfo<TType, TProperty>
            Type             genericPropertyType = typeof(JsonPropertyInfo <,>).MakeGenericType(classType, propertyType);
            JsonPropertyInfo jsonInfo            = (JsonPropertyInfo)Activator.CreateInstance(
                genericPropertyType,
                BindingFlags.Instance | BindingFlags.NonPublic,
                binder: null,
                new object[] { classType, propertyType, propertyInfo, collectionElementType, options },
                culture: null);

            if (propertyInfo != null)
            {
                string propertyName = propertyInfo.Name;

                // At this point propertyName is valid UTF16, so just call the simple UTF16->UTF8 encoder.
                byte[] propertyNameBytes = Encoding.UTF8.GetBytes(propertyName);
                jsonInfo._name = propertyNameBytes;

                // Cache the escaped name.
                int valueIdx = JsonWriterHelper.NeedsEscaping(propertyNameBytes);
                if (valueIdx == -1)
                {
                    jsonInfo._escapedName = propertyNameBytes;
                }
                else
                {
                    int length = JsonWriterHelper.GetMaxEscapedLength(propertyNameBytes.Length, valueIdx);

                    byte[] tempArray = ArrayPool <byte> .Shared.Rent(length);

                    JsonWriterHelper.EscapeString(propertyNameBytes, tempArray, valueIdx, out int written);
                    jsonInfo._escapedName = new byte[written];
                    tempArray.CopyTo(jsonInfo._escapedName, 0);

                    // We clear the array because it is "user data" (although a property name).
                    ArrayPool <byte> .Shared.Return(tempArray, clearArray : true);
                }

                _property_refs.Add(new PropertyRef(GetKey(propertyNameBytes), jsonInfo));
            }
            else
            {
                // A single property or an IEnumerable
                _property_refs.Add(new PropertyRef(0, jsonInfo));
            }
        }
Ejemplo n.º 3
0
        public void WriteObjectOrArrayStart(ClassType classType, Utf8JsonWriter writer, bool writeNull = false)
        {
            if (JsonPropertyInfo?.EscapedName != null)
            {
                WriteObjectOrArrayStart(classType, JsonPropertyInfo?.EscapedName, writer, writeNull);
            }
            else if (KeyName != null)
            {
                byte[] pooledKey = null;
                byte[] utf8Key   = Encoding.UTF8.GetBytes(KeyName);
                int    length    = JsonWriterHelper.GetMaxEscapedLength(utf8Key.Length, 0);

                Span <byte> escapedKey = length <= JsonConstants.StackallocThreshold ?
                                         stackalloc byte[length] :
                                         (pooledKey = ArrayPool <byte> .Shared.Rent(length));

                JsonWriterHelper.EscapeString(utf8Key, escapedKey, 0, out int written);
                Span <byte> propertyName = escapedKey.Slice(0, written);

                WriteObjectOrArrayStart(classType, propertyName, writer, writeNull);

                if (pooledKey != null)
                {
                    ArrayPool <byte> .Shared.Return(pooledKey);
                }
            }
            else
            {
                Debug.Assert(writeNull == false);

                // Write start without a property name.
                if (classType == ClassType.Object || classType == ClassType.Dictionary)
                {
                    writer.WriteStartObject();
                    StartObjectWritten = true;
                }
                else
                {
                    Debug.Assert(classType == ClassType.Enumerable);
                    writer.WriteStartArray();
                }
            }
        }
Ejemplo n.º 4
0
        private void AddProperty(Type propertyType, PropertyInfo propertyInfo, Type classType, JsonSerializerOptions options)
        {
            JsonPropertyInfo jsonInfo = CreateProperty(propertyType, propertyType, propertyInfo, classType, options);

            if (propertyInfo != null)
            {
                string propertyName = propertyInfo.Name;

                // At this point propertyName is valid UTF16, so just call the simple UTF16->UTF8 encoder.
                byte[] propertyNameBytes = Encoding.UTF8.GetBytes(propertyName);
                jsonInfo._name = propertyNameBytes;

                // Cache the escaped name.
                int valueIdx = JsonWriterHelper.NeedsEscaping(propertyNameBytes);
                if (valueIdx == -1)
                {
                    jsonInfo._escapedName = propertyNameBytes;
                }
                else
                {
                    int length = JsonWriterHelper.GetMaxEscapedLength(propertyNameBytes.Length, valueIdx);

                    byte[] tempArray = ArrayPool <byte> .Shared.Rent(length);

                    JsonWriterHelper.EscapeString(propertyNameBytes, tempArray, valueIdx, out int written);
                    jsonInfo._escapedName = new byte[written];
                    tempArray.CopyTo(jsonInfo._escapedName, 0);

                    // We clear the array because it is "user data" (although a property name).
                    new Span <byte>(tempArray, 0, written).Clear();
                    ArrayPool <byte> .Shared.Return(tempArray);
                }

                _propertyRefs.Add(new PropertyRef(GetKey(propertyNameBytes), jsonInfo));
            }
            else
            {
                // A single property or an IEnumerable
                _propertyRefs.Add(new PropertyRef(0, jsonInfo));
            }
        }
Ejemplo n.º 5
0
        private void DeterminePropertyName(JsonSerializerOptions options)
        {
            if (PropertyInfo == null)
            {
                return;
            }

            JsonPropertyNameAttribute nameAttribute = GetAttribute <JsonPropertyNameAttribute>(PropertyInfo);

            if (nameAttribute != null)
            {
                string name = nameAttribute.Name;
                if (name == null)
                {
                    ThrowHelper.ThrowInvalidOperationException_SerializerPropertyNameNull(ParentClassType, this);
                }

                NameAsString = name;
            }
            else if (options.PropertyNamingPolicy != null)
            {
                string name = options.PropertyNamingPolicy.ConvertName(PropertyInfo.Name);
                if (name == null)
                {
                    ThrowHelper.ThrowInvalidOperationException_SerializerPropertyNameNull(ParentClassType, this);
                }

                NameAsString = name;
            }
            else
            {
                NameAsString = PropertyInfo.Name;
            }

            Debug.Assert(NameAsString != null);

            // At this point propertyName is valid UTF16, so just call the simple UTF16->UTF8 encoder.
            Name = Encoding.UTF8.GetBytes(NameAsString);

            // Set the compare name.
            if (options.PropertyNameCaseInsensitive)
            {
                NameUsedToCompareAsString = NameAsString.ToUpperInvariant();
                NameUsedToCompare         = Encoding.UTF8.GetBytes(NameUsedToCompareAsString);
            }
            else
            {
                NameUsedToCompareAsString = NameAsString;
                NameUsedToCompare         = Name;
            }

            // Cache the escaped name.
#if true
            // temporary behavior until the writer can accept escaped string.
            EscapedName = Name;
#else
            int valueIdx = JsonWriterHelper.NeedsEscaping(_name);
            if (valueIdx == -1)
            {
                _escapedName = _name;
            }
            else
            {
                byte[] pooledName = null;
                int    length     = JsonWriterHelper.GetMaxEscapedLength(_name.Length, valueIdx);

                Span <byte> escapedName = length <= JsonConstants.StackallocThreshold ?
                                          stackalloc byte[length] :
                                          (pooledName = ArrayPool <byte> .Shared.Rent(length));

                JsonWriterHelper.EscapeString(_name, escapedName, 0, out int written);

                _escapedName = escapedName.Slice(0, written).ToArray();

                if (pooledName != null)
                {
                    // We clear the array because it is "user data" (although a property name).
                    new Span <byte>(pooledName, 0, written).Clear();
                    ArrayPool <byte> .Shared.Return(pooledName);
                }
            }
#endif
        }
Ejemplo n.º 6
0
        private void DeterminePropertyName(JsonSerializerOptions options)
        {
            if (PropertyInfo != null)
            {
                JsonPropertyNameAttribute nameAttribute = GetAttribute <JsonPropertyNameAttribute>();
                if (nameAttribute != null)
                {
                    NameAsString = nameAttribute.Name;

                    // This is detected and thrown by caller.
                    if (NameAsString == null)
                    {
                        return;
                    }
                }
                else if (options.PropertyNamingPolicy != null)
                {
                    NameAsString = options.PropertyNamingPolicy.ConvertName(PropertyInfo.Name);

                    // This is detected and thrown by caller.
                    if (NameAsString == null)
                    {
                        return;
                    }
                }
                else
                {
                    NameAsString = PropertyInfo.Name;
                }

                // At this point propertyName is valid UTF16, so just call the simple UTF16->UTF8 encoder.
                _name = Encoding.UTF8.GetBytes(NameAsString);

                // Set the compare name.
                if (options.PropertyNameCaseInsensitive)
                {
                    CompareNameAsString = NameAsString.ToUpperInvariant();
                    _compareName        = Encoding.UTF8.GetBytes(CompareNameAsString);
                }
                else
                {
                    CompareNameAsString = NameAsString;
                    _compareName        = _name;
                }

                // Cache the escaped name.
                int valueIdx = JsonWriterHelper.NeedsEscaping(_name);
                if (valueIdx == -1)
                {
                    _escapedName = _name;
                }
                else
                {
                    int length = JsonWriterHelper.GetMaxEscapedLength(_name.Length, valueIdx);

                    byte[] tempArray = ArrayPool <byte> .Shared.Rent(length);

                    JsonWriterHelper.EscapeString(_name, tempArray, valueIdx, out int written);
                    _escapedName = new byte[written];
                    tempArray.CopyTo(_escapedName, 0);

                    // We clear the array because it is "user data" (although a property name).
                    new Span <byte>(tempArray, 0, written).Clear();
                    ArrayPool <byte> .Shared.Return(tempArray);
                }
            }
        }