| File: System\Text\Json\Nodes\JsonValueOfT.cs | Web Access |
| Project: src\runtime\src\libraries\System.Text.Json\src\System.Text.Json.csproj (System.Text.Json) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; using System.Diagnostics.CodeAnalysis; namespace System.Text.Json.Nodes { [DebuggerDisplay("{ToJsonString(),nq}")] [DebuggerTypeProxy(typeof(JsonValue<>.DebugView))] internal abstract class JsonValue<TValue> : JsonValue { internal readonly TValue Value; // keep as a field for direct access to avoid copies protected JsonValue(TValue value, JsonNodeOptions? options) : base(options) { Debug.Assert(value is not null); Debug.Assert(value is not JsonElement or JsonElement { ValueKind: not JsonValueKind.Null }); Debug.Assert(value is not JsonNode); Value = value; } public override T GetValue<T>() { // If no conversion is needed, just return the raw value. if (Value is T returnValue) { return returnValue; } // Currently we do not support other conversions. // Generics (and also boxing) do not support standard cast operators say from 'long' to 'int', // so attempting to cast here would throw InvalidCastException. ThrowHelper.ThrowInvalidOperationException_NodeUnableToConvert(typeof(TValue), typeof(T)); return default!; } public override bool TryGetValue<T>([NotNullWhen(true)] out T value) { // If no conversion is needed, just return the raw value. if (Value is T returnValue) { value = returnValue; return true; } // Currently we do not support other conversions. // Generics (and also boxing) do not support standard cast operators say from 'long' to 'int', // so attempting to cast here would throw InvalidCastException. value = default!; return false; } /// <summary> /// Whether <typeparamref name="TValue"/> is a built-in type that admits primitive JsonValue representation. /// </summary> internal static bool TypeIsSupportedPrimitive => s_valueKind.HasValue; private static readonly JsonValueKind? s_valueKind = DetermineValueKindForType(typeof(TValue)); /// <summary> /// Determines the JsonValueKind for the value of a built-in type. /// </summary> private protected static JsonValueKind DetermineValueKind(TValue value) { Debug.Assert(s_valueKind is not null, "Should only be invoked for types that are supported primitives."); if (value is bool boolean) { // Boolean requires special handling since kind varies by value. return boolean ? JsonValueKind.True : JsonValueKind.False; } return s_valueKind.Value; } /// <summary> /// Precomputes the JsonValueKind for a given built-in type where possible. /// </summary> private static JsonValueKind? DetermineValueKindForType(Type type) { if (type.IsEnum) { return null; // Can vary depending on converter configuration and value. } if (Nullable.GetUnderlyingType(type) is Type underlyingType) { // Because JsonNode excludes null values, we can identify with the value kind of the underlying type. return DetermineValueKindForType(underlyingType); } if (type == typeof(DateTime) || type == typeof(DateTimeOffset) || type == typeof(TimeSpan) || #if NET type == typeof(DateOnly) || type == typeof(TimeOnly) || #endif type == typeof(Guid) || type == typeof(Uri) || type == typeof(Version)) { return JsonValueKind.String; } #if NET if (type == typeof(Half) || type == typeof(UInt128) || type == typeof(Int128)) { return JsonValueKind.Number; } #endif #if NET11_0_OR_GREATER if (type == typeof(System.Numerics.BFloat16) || type == typeof(System.Numerics.Decimal32) || type == typeof(System.Numerics.Decimal64) || type == typeof(System.Numerics.Decimal128)) { return JsonValueKind.Number; } #endif return Type.GetTypeCode(type) switch { TypeCode.Boolean => JsonValueKind.Undefined, // Can vary dependending on value. TypeCode.SByte => JsonValueKind.Number, TypeCode.Byte => JsonValueKind.Number, TypeCode.Int16 => JsonValueKind.Number, TypeCode.UInt16 => JsonValueKind.Number, TypeCode.Int32 => JsonValueKind.Number, TypeCode.UInt32 => JsonValueKind.Number, TypeCode.Int64 => JsonValueKind.Number, TypeCode.UInt64 => JsonValueKind.Number, TypeCode.Single => JsonValueKind.Number, TypeCode.Double => JsonValueKind.Number, TypeCode.Decimal => JsonValueKind.Number, TypeCode.String => JsonValueKind.String, TypeCode.Char => JsonValueKind.String, _ => null, }; } [ExcludeFromCodeCoverage] // Justification = "Design-time" [DebuggerDisplay("{Json,nq}")] private sealed class DebugView { [DebuggerBrowsable(DebuggerBrowsableState.Never)] public JsonValue<TValue> _node; public DebugView(JsonValue<TValue> node) { _node = node; } public string Json => _node.ToJsonString(); public string Path => _node.GetPath(); public TValue? Value => _node.Value; } } }