Skip to content

Commit

Permalink
Merged PR 72275: Extend attribute info
Browse files Browse the repository at this point in the history
Simplify creation of custom attributes, and add some extra attributes.
  • Loading branch information
Corniel committed Nov 21, 2024
1 parent 5b3a955 commit 159eb3c
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 15 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using System.Text.Json;
using System.Text.Json.Serialization;

namespace Open_API.JSON_serialization_specs;

public class Serializes
{
[Test]
public void Model_with_derived_types()
{
var json = @"{""Items"":[{""Value1"":""1.34534"",""Type"":""Derived1""},{""Value2"":""2.85464"",""Type"":""Derived2""}]}";

var model = JsonSerializer.Deserialize<MyContainer>(json);

model.Should().BeEquivalentTo(new MyContainer
{
Items =
[
new Derived1{ Type = "Derived1", Value1 = "1.34534" },
new Derived2{ Type = "Derived2", Value2 = "2.85464" },
]
});
}
}

public class Deserializes
{
[Test]
public void Model_with_derived_types()
{
var model = new MyContainer
{
Items =
[
new Derived1{ Type = "Derived1", Value1 = "1.34534" },
new Derived2{ Type = "Derived2", Value2 = "2.85464" },
]
};

var json = JsonSerializer.Serialize(model);


Console.WriteLine(json);
}
}


internal sealed record MyContainer
{
public MyBase[] Items { get; init; } = [];
}

[JsonDerivedType(typeof(Derived1))]
[JsonDerivedType(typeof(Derived2))]
internal record MyBase
{
public string? Type { get; init; }
}
internal sealed record Derived1 : MyBase
{
public string? Value1 { get; init; }
}

internal sealed record Derived2 : MyBase
{
public string? Value2 { get; init; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ public void ctor_arguments()

[Test]
public void parameter_sets()
=> new AttributeInfo(typeof(TestAttribute),
null, KeyValuePair.Create("Author", (object?)"Qowaiv"))
=> new AttributeInfo(typeof(TestAttribute), null, new { Author = "Qowaiv" })
.Should().HaveContent("[NUnit.Framework.Test(Author = \"Qowaiv\")]\r\n");

[Test]
Expand All @@ -32,11 +31,9 @@ public class Equaly
[Test]
public void by_value()
{
var attr = new AttributeInfo(typeof(TestAttribute),
null, KeyValuePair.Create("Author", (object?)"Qowaiv"));
var attr = new AttributeInfo(typeof(TestAttribute), null, new { Author = "Qowaiv" });

var ottr = new AttributeInfo(typeof(TestAttribute),
null, KeyValuePair.Create("Author", (object?)"Qowaiv"));
var ottr = new AttributeInfo(typeof(TestAttribute), null, new { Author = "Qowaiv" });

attr.Equals(ottr).Should().BeTrue();
}
Expand Down
6 changes: 6 additions & 0 deletions src/Qowaiv.CodeGeneration/Nill.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Qowaiv.CodeGeneration;

public sealed class Nill

Check warning on line 3 in src/Qowaiv.CodeGeneration/Nill.cs

View workflow job for this annotation

GitHub Actions / build

Missing XML comment for publicly visible type or member 'Nill'
{
public static readonly Nill Value = new();

Check warning on line 5 in src/Qowaiv.CodeGeneration/Nill.cs

View workflow job for this annotation

GitHub Actions / build

Missing XML comment for publicly visible type or member 'Nill.Value'
}
33 changes: 24 additions & 9 deletions src/Qowaiv.CodeGeneration/Syntax/AttributeInfo.Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ public partial class AttributeInfo
/// <summary><see cref="Newtonsoft.Json.JsonConstructorAttribute"/>.</summary>
public static readonly AttributeInfo Newtonsoft_Json_JsonConstructor = new(typeof(Newtonsoft.Json.JsonConstructorAttribute));

/// <summary><see cref="Qowaiv.Diagnostics.Contracts.InheritableAttribute"/>.</summary>
public static readonly AttributeInfo Qowaiv_Diagnostics_Contracts_Inheritable = new(typeof(Qowaiv.Diagnostics.Contracts.InheritableAttribute));

/// <summary><see cref="Qowaiv.Validation.DataAnnotations.AnyAttribute"/>.</summary>
public static readonly AttributeInfo Qowaiv_Validation_DataAnnotations_Any = new(typeof(Qowaiv.Validation.DataAnnotations.AnyAttribute));

Expand Down Expand Up @@ -68,10 +71,24 @@ public static AttributeInfo Qowaiv_Validation_DataAnnotations_AllowedValues(para
public static AttributeInfo Qowaiv_Validation_DataAnnotations_MultipleOf(double factor)
=> new(typeof(Qowaiv.Validation.DataAnnotations.MultipleOfAttribute), [factor]);

/// <summary><see cref="System.Text.Json.Serialization.JsonPolymorphicAttribute"/>.</summary>
[Pure]
public static AttributeInfo System_Text_Json_SerializationJsonPolymorphic(
string name,
System.Text.Json.Serialization.JsonUnknownDerivedTypeHandling? handling = default,
bool? ignoreUnrecognized = false) => new(
typeof(System.Text.Json.Serialization.JsonPolymorphicAttribute),
[name],
new
{
UnknownDerivedTypeHandling = handling,
IgnoreUnrecognizedTypeDiscriminators = ignoreUnrecognized,
});

/// <inheritdoc cref="System_Text_Json_Serialization_JsonConverter(Type)"/>
[Pure]
public static AttributeInfo System_Text_Json_Serialization_JsonConverter<T>() where T: System.Text.Json.Serialization.JsonConverter
=> System_Text_Json_Serialization_JsonConverter(typeof(T));
public static AttributeInfo System_Text_Json_Serialization_JsonConverter<TConverter>() where TConverter : System.Text.Json.Serialization.JsonConverter
=> System_Text_Json_Serialization_JsonConverter(typeof(TConverter));

/// <summary><see cref="System.Text.Json.Serialization.JsonConverterAttribute"/>.</summary>
[Pure]
Expand All @@ -80,13 +97,14 @@ public static AttributeInfo System_Text_Json_Serialization_JsonConverter(Type ty

/// <summary><see cref="System.Text.Json.Serialization.JsonDerivedTypeAttribute"/>.</summary>
[Pure]
public static AttributeInfo System_Text_Json_Serialization_JsonDerivedType(Type type)
=> new(typeof(System.Text.Json.Serialization.JsonDerivedTypeAttribute), [type]);
public static AttributeInfo System_Text_Json_Serialization_JsonDerivedType(Type type, string? discriminator = null) => new(
typeof(System.Text.Json.Serialization.JsonDerivedTypeAttribute),
discriminator is { } ? [type, discriminator] : [type]);

/// <summary><see cref="System.Text.Json.Serialization.JsonDerivedTypeAttribute"/>.</summary>
[Pure]
public static AttributeInfo System_Text_Json_Serialization_JsonIgnore(System.Text.Json.Serialization.JsonIgnoreCondition condition)
=> new(typeof(System.Text.Json.Serialization.JsonIgnoreAttribute), null, Kvp(nameof(System.Text.Json.Serialization.JsonIgnoreAttribute.Condition), condition));
=> new(typeof(System.Text.Json.Serialization.JsonIgnoreAttribute), null, new { Condition = condition });

/// <summary><see cref="System.Text.Json.Serialization.JsonPropertyNameAttribute"/>.</summary>
[Pure]
Expand All @@ -96,8 +114,5 @@ public static AttributeInfo System_Text_Json_Serialization_JsonPropertyName(stri
/// <summary><see cref="System.Runtime.Serialization.EnumMemberAttribute"/>.</summary>
[Pure]
public static AttributeInfo System_Runtime_Serialization_EnumMember(string? value)
=> new(typeof(System.Runtime.Serialization.EnumMemberAttribute), null, Kvp("Value", (object?)value));

[Pure]
private static KeyValuePair<string, object?> Kvp(string key, object? value) => new(key, value);
=> new(typeof(System.Runtime.Serialization.EnumMemberAttribute), null, new { Value = (object?)value ?? Nill.Value });
}
18 changes: 18 additions & 0 deletions src/Qowaiv.CodeGeneration/Syntax/AttributeInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,22 @@ namespace Qowaiv.CodeGeneration.Syntax;
public sealed partial class AttributeInfo : Code, IEquatable<AttributeInfo>
{
/// <summary>Initializes a new instance of the <see cref="AttributeInfo"/> class.</summary>
[Obsolete("Use new AttributeInfo(Type, object[]?, dynamic) instead.")]
public AttributeInfo(Type attribute, object[]? ctorArguments = null, params KeyValuePair<string, object?>[] propertyValues)
{
AttributeType = Guard.NotNull(attribute);
CtorArguments = ctorArguments ?? [];
PropertyValues = propertyValues ?? [];
}

/// <summary>Initializes a new instance of the <see cref="AttributeInfo"/> class.</summary>
public AttributeInfo(Type attribute, object[]? ctorArguments = null, dynamic? propertyValues = null)
{
AttributeType = Guard.NotNull(attribute);
CtorArguments = ctorArguments ?? [];
PropertyValues = propertyValues is null ? [] : FromDynamic(propertyValues);
}

/// <summary>The type of the attribute.</summary>
public Type AttributeType { get; }

Expand Down Expand Up @@ -120,4 +129,13 @@ public override int GetHashCode()

/// <summary>Returns false if both have the same values.</summary>
public static bool operator !=(AttributeInfo? l, AttributeInfo? r) => !(l == r);

/// <summary>Creates a dictionary from a a dynamic object.</summary>
[Pure]
private static IReadOnlyCollection<KeyValuePair<string, object?>> FromDynamic(object obj)
=> obj.GetType()
.GetProperties()
.Select(p => KeyValuePair.Create(p.Name, p.GetValue(obj)))
.Where(kvp => kvp.Value is { })
.ToDictionary();
}
1 change: 1 addition & 0 deletions src/Qowaiv.CodeGeneration/Syntax/Literal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public void WriteTo(CSharpWriter writer)
Guard.NotNull(writer);
_ = Value switch
{
Nill or
null /*.........*/ => writer.Write("null"),
Type type /*....*/ => writer.Write("typeof(").Write(type).Write(')'),
bool boolean /*.*/ => writer.Write(boolean ? "true" : "false"),
Expand Down

0 comments on commit 159eb3c

Please sign in to comment.