* Fix a couple of JsonConstructor bugs & clean up JsonParameterInfo implementation.
* add test coverage for ignored null values
* fix whitespace
public static object? GetDefaultValue(this ParameterInfo parameterInfo)
{
+ Type parameterType = parameterInfo.ParameterType;
object? defaultValue = parameterInfo.DefaultValue;
+ if (defaultValue is null)
+ {
+ return null;
+ }
+
// DBNull.Value is sometimes used as the default value (returned by reflection) of nullable params in place of null.
- if (defaultValue == DBNull.Value && parameterInfo.ParameterType != typeof(DBNull))
+ if (defaultValue == DBNull.Value && parameterType != typeof(DBNull))
{
return null;
}
+#if !BUILDING_SOURCE_GENERATOR
+ // Default values of enums or nullable enums are represented using the underlying type and need to be cast explicitly
+ // cf. https://github.com/dotnet/runtime/issues/68647
+ if (parameterType.IsEnum)
+ {
+ return Enum.ToObject(parameterType, defaultValue);
+ }
+
+ if (Nullable.GetUnderlyingType(parameterType) is Type underlyingType && underlyingType.IsEnum)
+ {
+ return Enum.ToObject(underlyingType, defaultValue);
+ }
+#endif
+
return defaultValue;
}
<Compile Include="System\Text\Json\Serialization\JsonStringEnumConverter.cs" />
<Compile Include="System\Text\Json\Serialization\JsonUnknownTypeHandling.cs" />
<Compile Include="System\Text\Json\Serialization\Metadata\FSharpCoreReflectionProxy.cs" />
- <Compile Include="System\Text\Json\Serialization\Metadata\DefaultValueHolder.cs" />
<Compile Include="System\Text\Json\Serialization\Metadata\JsonCollectionInfoValuesOfTCollection.cs" />
<Compile Include="System\Text\Json\Serialization\Metadata\JsonMetadataServices.Collections.cs" />
<Compile Include="System\Text\Json\Serialization\Metadata\JsonMetadataServices.Converters.cs" />
/// </summary>
internal sealed class Arguments<TArg0, TArg1, TArg2, TArg3>
{
- public TArg0 Arg0 = default!;
- public TArg1 Arg1 = default!;
- public TArg2 Arg2 = default!;
- public TArg3 Arg3 = default!;
+ public TArg0? Arg0;
+ public TArg1? Arg1;
+ public TArg2? Arg2;
+ public TArg3? Arg3;
}
}
Debug.Assert(jsonParameterInfo.ShouldDeserialize);
Debug.Assert(jsonParameterInfo.Options != null);
- bool success = jsonParameterInfo.ConverterBase.TryReadAsObject(ref reader, TypeToConvert, jsonParameterInfo.Options!, ref state, out object? arg);
+ bool success = jsonParameterInfo.EffectiveConverter.TryReadAsObject(ref reader, TypeToConvert, jsonParameterInfo.Options!, ref state, out object? arg);
if (success && !(arg == null && jsonParameterInfo.IgnoreNullTokensOnRead))
{
- ((object[])state.Current.CtorArgumentState!.Arguments)[jsonParameterInfo.ClrInfo.Position] = arg!;
+ ((object[])state.Current.CtorArgumentState!.Arguments)[jsonParameterInfo.Position] = arg!;
// if this is required property IgnoreNullTokensOnRead will always be false because we don't allow for both to be true
state.Current.MarkRequiredPropertyAsRead(jsonParameterInfo.MatchingProperty);
for (int i = 0; i < typeInfo.ParameterCount; i++)
{
JsonParameterInfo parameterInfo = cache[i].Value;
- arguments[parameterInfo.ClrInfo.Position] = parameterInfo.DefaultValue;
+ arguments[parameterInfo.Position] = parameterInfo.DefaultValue;
}
state.Current.CtorArgumentState!.Arguments = arguments;
bool success;
- switch (jsonParameterInfo.ClrInfo.Position)
+ switch (jsonParameterInfo.Position)
{
case 0:
success = TryRead(ref state, ref reader, jsonParameterInfo, out arguments.Arg0);
scoped ref ReadStack state,
ref Utf8JsonReader reader,
JsonParameterInfo jsonParameterInfo,
- out TArg arg)
+ out TArg? arg)
{
Debug.Assert(jsonParameterInfo.ShouldDeserialize);
- Debug.Assert(jsonParameterInfo.Options != null);
var info = (JsonParameterInfo<TArg>)jsonParameterInfo;
- var converter = (JsonConverter<TArg>)jsonParameterInfo.ConverterBase;
- bool success = converter.TryRead(ref reader, info.PropertyType, info.Options!, ref state, out TArg? value);
+ bool success = info.EffectiveConverter.TryRead(ref reader, info.ParameterType, info.Options, ref state, out TArg? value);
- arg = value == null && jsonParameterInfo.IgnoreNullTokensOnRead
- ? (TArg?)info.DefaultValue! // Use default value specified on parameter, if any.
- : value!;
+ arg = value is null && jsonParameterInfo.IgnoreNullTokensOnRead
+ ? info.DefaultValue // Use default value specified on parameter, if any.
+ : value;
if (success)
{
for (int i = 0; i < typeInfo.ParameterCount; i++)
{
JsonParameterInfo parameterInfo = cache[i].Value;
-
- // We can afford not to set default values for ctor arguments when we should't deserialize because the
- // type parameters of the `Arguments` type provide default semantics that work well with value types.
- if (parameterInfo.ShouldDeserialize)
+ switch (parameterInfo.Position)
{
- int position = parameterInfo.ClrInfo.Position;
-
- switch (position)
- {
- case 0:
- arguments.Arg0 = ((JsonParameterInfo<TArg0>)parameterInfo).TypedDefaultValue!;
- break;
- case 1:
- arguments.Arg1 = ((JsonParameterInfo<TArg1>)parameterInfo).TypedDefaultValue!;
- break;
- case 2:
- arguments.Arg2 = ((JsonParameterInfo<TArg2>)parameterInfo).TypedDefaultValue!;
- break;
- case 3:
- arguments.Arg3 = ((JsonParameterInfo<TArg3>)parameterInfo).TypedDefaultValue!;
- break;
- default:
- Debug.Fail("More than 4 params: we should be in override for LargeObjectWithParameterizedConstructorConverter.");
- throw new InvalidOperationException();
- }
+ case 0:
+ arguments.Arg0 = ((JsonParameterInfo<TArg0>)parameterInfo).DefaultValue;
+ break;
+ case 1:
+ arguments.Arg1 = ((JsonParameterInfo<TArg1>)parameterInfo).DefaultValue;
+ break;
+ case 2:
+ arguments.Arg2 = ((JsonParameterInfo<TArg2>)parameterInfo).DefaultValue;
+ break;
+ case 3:
+ arguments.Arg3 = ((JsonParameterInfo<TArg3>)parameterInfo).DefaultValue;
+ break;
+ default:
+ Debug.Fail("More than 4 params: we should be in override for LargeObjectWithParameterizedConstructorConverter.");
+ throw new InvalidOperationException();
}
}
// Returning false below will cause the read-ahead functionality to finish the read.
state.Current.PropertyState = StackFramePropertyState.ReadValue;
- if (!SingleValueReadWithReadAhead(jsonParameterInfo.ConverterBase.RequiresReadAhead, ref reader, ref state))
+ if (!SingleValueReadWithReadAhead(jsonParameterInfo.EffectiveConverter.RequiresReadAhead, ref reader, ref state))
{
return false;
}
throw new InvalidOperationException();
}
- internal abstract JsonParameterInfo CreateJsonParameterInfo();
-
internal abstract JsonConverter<TTarget> CreateCastingConverter<TTarget>();
/// <summary>
/// </returns>
public abstract JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options);
- internal override JsonParameterInfo CreateJsonParameterInfo()
- {
- Debug.Fail("We should never get here.");
-
- throw new InvalidOperationException();
- }
-
internal sealed override Type? KeyType => null;
internal sealed override Type? ElementType => null;
return new JsonTypeInfo<T>(this, options);
}
- internal sealed override JsonParameterInfo CreateJsonParameterInfo()
- {
- return new JsonParameterInfo<T>();
- }
-
internal sealed override JsonConverter<TTarget> CreateCastingConverter<TTarget>()
{
if (this is JsonConverter<TTarget> conv)
+++ /dev/null
-// 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.CodeAnalysis;
-
-namespace System.Text.Json.Serialization.Metadata
-{
- /// <summary>
- /// Helper class used for calculating the default value for a given System.Type instance.
- /// </summary>
- internal sealed class DefaultValueHolder
- {
- [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2067:UnrecognizedReflectionPattern",
- Justification = "GetUninitializedObject is only called on a struct. You can always create an instance of a struct.")]
- private DefaultValueHolder(Type type)
- {
- if (type.IsValueType && Nullable.GetUnderlyingType(type) == null)
- {
-#if NETCOREAPP
- DefaultValue = System.Runtime.CompilerServices.RuntimeHelpers.GetUninitializedObject(type);
-#else
- DefaultValue = System.Runtime.Serialization.FormatterServices.GetUninitializedObject(type);
-#endif
- }
- }
-
- /// <summary>
- /// Returns the default value for the specified type.
- /// </summary>
- public object? DefaultValue { get; }
-
- /// <summary>
- /// Returns true if <param name="value"/> contains only default values.
- /// </summary>
- public bool IsDefaultValue(object value) => DefaultValue is null ? value is null : DefaultValue.Equals(value);
-
- /// <summary>
- /// Creates a holder instance representing a type.
- /// </summary>
- public static DefaultValueHolder CreateHolder(Type type) => new DefaultValueHolder(type);
- }
-}
/// </summary>
internal abstract class JsonParameterInfo
{
- private JsonTypeInfo? _jsonTypeInfo;
+ public JsonConverter EffectiveConverter => MatchingProperty.EffectiveConverter;
- public JsonConverter ConverterBase { get; private set; } = null!;
+ // The default value of the parameter. This is `DefaultValue` of the `ParameterInfo`, if specified, or the `default` for the `ParameterType`.
+ public object? DefaultValue { get; private protected init; }
- private protected bool MatchingPropertyCanBeNull { get; private set; }
+ public bool IgnoreNullTokensOnRead { get; }
- // The default value of the parameter. This is `DefaultValue` of the `ParameterInfo`, if specified, or the CLR `default` for the `ParameterType`.
- public object? DefaultValue { get; private protected set; }
-
- public bool IgnoreNullTokensOnRead { get; private set; }
-
- // Options can be referenced here since all JsonPropertyInfos originate from a JsonTypeInfo that is cached on JsonSerializerOptions.
- public JsonSerializerOptions? Options { get; set; } // initialized in Init method
+ public JsonSerializerOptions Options { get; }
// The name of the parameter as UTF-8 bytes.
- public byte[] NameAsUtf8Bytes { get; private set; } = null!;
+ public byte[] NameAsUtf8Bytes { get; }
- public JsonNumberHandling? NumberHandling { get; private set; }
+ public JsonNumberHandling? NumberHandling { get; }
- // Using a field to avoid copy semantics.
- public JsonParameterInfoValues ClrInfo = null!;
+ public int Position { get; }
- public JsonTypeInfo JsonTypeInfo
- {
- get
- {
- Debug.Assert(Options != null);
- Debug.Assert(ShouldDeserialize);
- return _jsonTypeInfo ??= Options.GetTypeInfoInternal(PropertyType);
- }
- set
- {
- // Used by JsonMetadataServices.
- Debug.Assert(_jsonTypeInfo == null);
- _jsonTypeInfo = value;
- }
- }
+ public JsonTypeInfo JsonTypeInfo => MatchingProperty.JsonTypeInfo;
- public Type PropertyType { get; set; } = null!;
+ public Type ParameterType { get; }
- public bool ShouldDeserialize { get; private set; }
+ public bool ShouldDeserialize { get; }
- public JsonPropertyInfo MatchingProperty { get; private set; } = null!;
+ public JsonPropertyInfo MatchingProperty { get; }
- public virtual void Initialize(JsonParameterInfoValues parameterInfo, JsonPropertyInfo matchingProperty, JsonSerializerOptions options)
+ public JsonParameterInfo(JsonParameterInfoValues parameterInfoValues, JsonPropertyInfo matchingProperty)
{
+ Debug.Assert(matchingProperty.IsConfigured);
+
MatchingProperty = matchingProperty;
- ClrInfo = parameterInfo;
- Options = options;
- ShouldDeserialize = true;
+ ShouldDeserialize = !matchingProperty.IsIgnored;
+ Options = matchingProperty.Options;
+ Position = parameterInfoValues.Position;
- PropertyType = matchingProperty.PropertyType;
- NameAsUtf8Bytes = matchingProperty.NameAsUtf8Bytes!;
- ConverterBase = matchingProperty.EffectiveConverter;
+ ParameterType = matchingProperty.PropertyType;
+ NameAsUtf8Bytes = matchingProperty.NameAsUtf8Bytes;
IgnoreNullTokensOnRead = matchingProperty.IgnoreNullTokensOnRead;
NumberHandling = matchingProperty.EffectiveNumberHandling;
- MatchingPropertyCanBeNull = matchingProperty.PropertyTypeCanBeNull;
- }
-
- /// <summary>
- /// Create a parameter that is ignored at run time. It uses the same type (typeof(sbyte)) to help
- /// prevent issues with unsupported types and helps ensure we don't accidently (de)serialize it.
- /// </summary>
- public static JsonParameterInfo CreateIgnoredParameterPlaceholder(
- JsonParameterInfoValues parameterInfo,
- JsonPropertyInfo matchingProperty,
- bool sourceGenMode)
- {
- JsonParameterInfo jsonParameterInfo = new JsonParameterInfo<sbyte>();
- jsonParameterInfo.ClrInfo = parameterInfo;
- jsonParameterInfo.PropertyType = matchingProperty.PropertyType;
- jsonParameterInfo.NameAsUtf8Bytes = matchingProperty.NameAsUtf8Bytes!;
-
- // TODO: https://github.com/dotnet/runtime/issues/60082.
- // Default value initialization for params mapping to ignored properties doesn't
- // account for the default value of optional parameters. This should be fixed.
-
- if (sourceGenMode)
- {
- // The <T> value in the matching JsonPropertyInfo<T> instance matches the parameter type.
- jsonParameterInfo.DefaultValue = matchingProperty.DefaultValue;
- }
- else
- {
- // The <T> value in the created JsonPropertyInfo<T> instance (sbyte)
- // doesn't match the parameter type, use reflection to get the default value.
- Type parameterType = parameterInfo.ParameterType;
-
- DefaultValueHolder holder;
- if (matchingProperty.Options.TryGetTypeInfoCached(parameterType, out JsonTypeInfo? typeInfo))
- {
- holder = typeInfo.DefaultValueHolder;
- }
- else
- {
- holder = DefaultValueHolder.CreateHolder(parameterInfo.ParameterType);
- }
-
- jsonParameterInfo.DefaultValue = holder.DefaultValue;
- }
-
- return jsonParameterInfo;
}
}
}
/// </summary>
internal sealed class JsonParameterInfo<T> : JsonParameterInfo
{
- public T TypedDefaultValue { get; private set; } = default!;
+ public new JsonConverter<T> EffectiveConverter => MatchingProperty.EffectiveConverter;
+ public new JsonPropertyInfo<T> MatchingProperty { get; }
+ public new T? DefaultValue { get; }
- public override void Initialize(JsonParameterInfoValues parameterInfo, JsonPropertyInfo matchingProperty, JsonSerializerOptions options)
+ public JsonParameterInfo(JsonParameterInfoValues parameterInfoValues, JsonPropertyInfo<T> matchingPropertyInfo)
+ : base(parameterInfoValues, matchingPropertyInfo)
{
- base.Initialize(parameterInfo, matchingProperty, options);
- InitializeDefaultValue(matchingProperty);
- }
-
- private void InitializeDefaultValue(JsonPropertyInfo matchingProperty)
- {
- Debug.Assert(ClrInfo.ParameterType == matchingProperty.PropertyType);
+ Debug.Assert(parameterInfoValues.ParameterType == typeof(T));
+ Debug.Assert(matchingPropertyInfo.IsConfigured);
- if (ClrInfo.HasDefaultValue)
- {
- object? defaultValue = ClrInfo.DefaultValue;
+ MatchingProperty = matchingPropertyInfo;
+ DefaultValue = parameterInfoValues.HasDefaultValue && parameterInfoValues.DefaultValue is not null
+ ? (T)parameterInfoValues.DefaultValue
+ : default;
- if (defaultValue == null && !matchingProperty.PropertyTypeCanBeNull)
- {
- DefaultValue = TypedDefaultValue;
- }
- else
- {
- DefaultValue = defaultValue;
- TypedDefaultValue = (T)defaultValue!;
- }
- }
- else
- {
- DefaultValue = TypedDefaultValue;
- }
+ base.DefaultValue = DefaultValue;
}
}
}
|| (shouldCheckForRequiredKeyword && memberInfo.HasRequiredMemberAttribute());
}
+ /// <summary>
+ /// Creates a <see cref="JsonPropertyInfo"/> instance whose type matches that of the current property.
+ /// </summary>
+ internal abstract JsonParameterInfo CreateJsonParameterInfo(JsonParameterInfoValues parameterInfoValues);
+
internal abstract bool GetMemberAndWriteJson(object obj, ref WriteStack state, Utf8JsonWriter writer);
internal abstract bool GetMemberAndWriteJsonExtensionData(object obj, ref WriteStack state, Utf8JsonWriter writer);
internal override object? DefaultValue => default(T);
internal override bool PropertyTypeCanBeNull => default(T) is null;
+ internal override JsonParameterInfo CreateJsonParameterInfo(JsonParameterInfoValues parameterInfoValues)
+ => new JsonParameterInfo<T>(parameterInfoValues, this);
internal new JsonConverter<T> EffectiveConverter
{
internal const string JsonObjectTypeName = "System.Text.Json.Nodes.JsonObject";
- internal delegate T ParameterizedConstructorDelegate<T, TArg0, TArg1, TArg2, TArg3>(TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3);
+ internal delegate T ParameterizedConstructorDelegate<T, TArg0, TArg1, TArg2, TArg3>(TArg0? arg0, TArg1? arg1, TArg2? arg2, TArg3? arg3);
/// <summary>
/// Indices of required properties.
private protected abstract JsonPropertyInfo CreatePropertyInfoForTypeInfo();
/// <summary>
- /// Returns a helper class used for computing the default value.
- /// </summary>
- internal DefaultValueHolder DefaultValueHolder => _defaultValueHolder ??= DefaultValueHolder.CreateHolder(Type);
- private DefaultValueHolder? _defaultValueHolder;
-
- /// <summary>
/// Gets or sets the type-level <see cref="JsonSerializerOptions.NumberHandling"/> override.
/// </summary>
/// <exception cref="InvalidOperationException">
Debug.Assert(ParameterCache is null);
JsonParameterInfoValues[] jsonParameters = ParameterInfoValues ?? Array.Empty<JsonParameterInfoValues>();
- bool sourceGenMode = Options.TypeInfoResolver is JsonSerializerContext;
-
var parameterCache = new JsonPropertyDictionary<JsonParameterInfo>(Options.PropertyNameCaseInsensitive, jsonParameters.Length);
// Cache the lookup from object property name to JsonPropertyInfo using a case-insensitive comparer.
Debug.Assert(matchingEntry.JsonPropertyInfo != null);
JsonPropertyInfo jsonPropertyInfo = matchingEntry.JsonPropertyInfo;
- JsonParameterInfo jsonParameterInfo = CreateConstructorParameter(parameterInfo, jsonPropertyInfo, sourceGenMode, Options);
+ JsonParameterInfo jsonParameterInfo = jsonPropertyInfo.CreateJsonParameterInfo(parameterInfo);
parameterCache.Add(jsonPropertyInfo.Name, jsonParameterInfo);
}
// It is invalid for the extension data property to bind to a constructor argument.
return new JsonPropertyDictionary<JsonPropertyInfo>(Options.PropertyNameCaseInsensitive, capacity);
}
- private static JsonParameterInfo CreateConstructorParameter(
- JsonParameterInfoValues parameterInfo,
- JsonPropertyInfo jsonPropertyInfo,
- bool sourceGenMode,
- JsonSerializerOptions options)
- {
- if (jsonPropertyInfo.IsIgnored)
- {
- return JsonParameterInfo.CreateIgnoredParameterPlaceholder(parameterInfo, jsonPropertyInfo, sourceGenMode);
- }
-
- JsonConverter converter = jsonPropertyInfo.EffectiveConverter;
- JsonParameterInfo jsonParameterInfo = converter.CreateJsonParameterInfo();
-
- jsonParameterInfo.Initialize(parameterInfo, jsonPropertyInfo, options);
-
- return jsonParameterInfo;
- }
-
private static JsonTypeInfoKind GetTypeInfoKind(Type type, JsonConverter converter)
{
if (type == typeof(object) && converter.CanBePolymorphic)
}
[Fact]
+ public async Task IgnoreNullValues_SetDefaultConstructorParameter_ToConstructorArguments_ThatCanBeNull()
+ {
+ var options = new JsonSerializerOptions { IgnoreNullValues = true };
+ NullArgTester result = await Serializer.DeserializeWrapper<NullArgTester>(@"{""String"":null}", options);
+ Assert.Equal("defaultStr", result.String);
+ }
+
+ [Fact]
public async Task NumerousSimpleAndComplexParameters()
{
var obj = await Serializer.DeserializeWrapper<ObjWCtorMixedParams>(ObjWCtorMixedParams.s_json);
{
string json = @"{""Prop"":20}";
var obj1 = await Serializer.DeserializeWrapper<SmallType_IgnoredProp_Bind_ParamWithDefaultValue>(json);
- Assert.Equal(0, obj1.Prop);
+ Assert.Equal(5, obj1.Prop);
var obj2 = await Serializer.DeserializeWrapper<SmallType_IgnoredProp_Bind_Param>(json);
Assert.Equal(0, obj2.Prop);
{
string json = @"{""Prop"":20}";
var obj1 = await Serializer.DeserializeWrapper<LargeType_IgnoredProp_Bind_ParamWithDefaultValue>(json);
- Assert.Equal(0, obj1.Prop);
+ Assert.Equal(5, obj1.Prop);
var obj2 = await Serializer.DeserializeWrapper<LargeType_IgnoredProp_Bind_Param>(json);
Assert.Equal(0, obj2.Prop);
ULong = @ulong;
}
}
+
+ [Fact]
+ public async Task TestTypeWithEnumParameters()
+ {
+ // Regression test for https://github.com/dotnet/runtime/issues/68647
+
+ var value = new TypeWithEnumParameters();
+
+ string json = await Serializer.SerializeWrapper(value);
+ Assert.Equal("""{"Value":"One","NullableValue":"Two"}""", json);
+
+ value = await Serializer.DeserializeWrapper<TypeWithEnumParameters>(json);
+ Assert.Equal(MyEnum.One, value.Value);
+ Assert.Equal(MyEnum.Two, value.NullableValue);
+
+ value = await Serializer.DeserializeWrapper<TypeWithEnumParameters>("{}");
+ Assert.Equal(MyEnum.One, value.Value);
+ Assert.Equal(MyEnum.Two, value.NullableValue);
+ }
+
+ public sealed class TypeWithEnumParameters
+ {
+ public MyEnum Value { get; }
+ public MyEnum? NullableValue { get; }
+
+ [JsonConstructor]
+ public TypeWithEnumParameters(MyEnum value = MyEnum.One, MyEnum? nullableValue = MyEnum.Two)
+ {
+ Value = value;
+ NullableValue = nullableValue;
+ }
+ }
+
+ [JsonConverter(typeof(JsonStringEnumConverter))]
+ public enum MyEnum
+ {
+ One = 1,
+ Two = 2,
+ }
+
+ [Fact]
+ public async Task TestClassWithIgnoredPropertyDefaultParam()
+ {
+ // Regression test for https://github.com/dotnet/runtime/issues/60082
+
+ string json = "{}";
+ ClassWithIgnoredPropertyDefaultParam result = await Serializer.DeserializeWrapper<ClassWithIgnoredPropertyDefaultParam>(json);
+ Assert.Equal(5, result.Y);
+ }
+
+ public class ClassWithIgnoredPropertyDefaultParam
+ {
+ public int X { get; }
+
+ [JsonIgnore]
+ public int Y { get; }
+
+ public ClassWithIgnoredPropertyDefaultParam(int x, int y = 5) => (X, Y) = (x, y);
+ }
}
}
public Point_3D_Struct Point3DStruct { get; }
public ImmutableArray<int> ImmutableArray { get; }
public int Int { get; }
+ public string String { get; }
- public NullArgTester(Point_3D_Struct point3DStruct, ImmutableArray<int> immutableArray, int @int = 50)
+ public NullArgTester(Point_3D_Struct point3DStruct, ImmutableArray<int> immutableArray, int @int = 50, string @string = "defaultStr")
{
Point3DStruct = point3DStruct;
ImmutableArray = immutableArray;
Int = @int;
+ String = @string;
}
}
public void Verify()
{
Assert.Equal(0, X);
- Assert.Equal(0, Y); // We don't set parameter default value here.
+ Assert.Equal(5, Y); // We use the default parameter of the constructor.
}
}
[JsonSerializable(typeof(ClassWithManyConstructorParameters))]
[JsonSerializable(typeof(ClassWithInvalidArray))]
[JsonSerializable(typeof(ClassWithInvalidDictionary))]
+ [JsonSerializable(typeof(TypeWithEnumParameters))]
+ [JsonSerializable(typeof(ClassWithIgnoredPropertyDefaultParam))]
internal sealed partial class ConstructorTestsContext_Metadata : JsonSerializerContext
{
}
[JsonSerializable(typeof(ClassWithManyConstructorParameters))]
[JsonSerializable(typeof(ClassWithInvalidArray))]
[JsonSerializable(typeof(ClassWithInvalidDictionary))]
+ [JsonSerializable(typeof(TypeWithEnumParameters))]
+ [JsonSerializable(typeof(ClassWithIgnoredPropertyDefaultParam))]
internal sealed partial class ConstructorTestsContext_Default : JsonSerializerContext
{
}