Skip to content

Json and Logging Source Generator should use consistent strategy in generated code #52279

@eerhardt

Description

@eerhardt

When you use the System.Text.Json source generator, the generated code looks like:

using ClassLibrary1;
using System.Runtime.CompilerServices;
using System.Text.Json.Serialization.Metadata;
using System.Text.Json.Serialization;
using System.Text.Json;

namespace ClassLibrary1.JsonSourceGeneration
{
    internal partial class JsonContext : JsonSerializerContext
    {
        private JsonTypeInfo<ClassLibrary1.Class1> _Class1;
        public JsonTypeInfo<ClassLibrary1.Class1> Class1
        {
            get
            {
                if (_Class1 == null)
                {
                    JsonConverter customConverter;
                    if (Options.Converters.Count > 0 && (customConverter = GetRuntimeProvidedCustomConverter(typeof(ClassLibrary1.Class1))) != null)
                    {
                        _Class1 = JsonMetadataServices.CreateValueInfo<ClassLibrary1.Class1>(Options, customConverter);
                    }
                    else
                    {
                        JsonTypeInfo<ClassLibrary1.Class1> objectInfo = JsonMetadataServices.CreateObjectInfo<ClassLibrary1.Class1>();
                        _Class1 = objectInfo;
    
                        JsonMetadataServices.InitializeObjectInfo(
                            objectInfo,
                            Options,
                            createObjectFunc: null,
                            Class1PropInitFunc,
                            default);
                    }
                }

                return _Class1;
            }
        }
        private static JsonPropertyInfo[] Class1PropInitFunc(JsonSerializerContext context)
        {
            JsonContext jsonContext = (JsonContext)context;
            JsonSerializerOptions options = context.Options;

            JsonPropertyInfo[] properties = System.Array.Empty<JsonPropertyInfo>();

            return properties;
        }
    }
}

When using the Logging Source Generator, the generated code looks like:

// <auto-generated/>
#nullable enable

namespace ClassLibrary1
{
    partial class Class1 
    {
        [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Logging.Generators", "6.0.0.0")]
        private readonly struct __HealthCheckErrorStruct : global::System.Collections.Generic.IReadOnlyList<global::System.Collections.Generic.KeyValuePair<string, object?>>
        {
            private readonly global::System.String _HealthCheckName;
            private readonly global::System.Double _ElapsedMilliseconds;

            public __HealthCheckErrorStruct(global::System.String HealthCheckName, global::System.Double ElapsedMilliseconds)
            {
                this._HealthCheckName = HealthCheckName;
                this._ElapsedMilliseconds = ElapsedMilliseconds;

            }

            public override string ToString()
            {
                var HealthCheckName = this._HealthCheckName;
                var ElapsedMilliseconds = this._ElapsedMilliseconds;

                return $"Health check {HealthCheckName} threw an unhandled exception after {ElapsedMilliseconds}ms";
            }

            public static string Format(__HealthCheckErrorStruct state, global::System.Exception? ex) => state.ToString();

            public int Count => 3;

            public global::System.Collections.Generic.KeyValuePair<string, object?> this[int index]
            {
                get => index switch
                {
                    0 => new global::System.Collections.Generic.KeyValuePair<string, object?>("HealthCheckName", this._HealthCheckName),
                    1 => new global::System.Collections.Generic.KeyValuePair<string, object?>("ElapsedMilliseconds", this._ElapsedMilliseconds),
                    2 => new global::System.Collections.Generic.KeyValuePair<string, object?>("{OriginalFormat}", "Health check {HealthCheckName} threw an unhandled exception after {ElapsedMilliseconds}ms"),

                    _ => throw new global::System.IndexOutOfRangeException(nameof(index)),  // return the same exception LoggerMessage.Define returns in this case
                };
            }

Notice a few differences:

  1. Logging Source Generator has // <auto-generated/> and #nullable enable at the top of the file. Json doesn't.
  2. Logging Source Generator uses GeneratedCodeAttribute on the generated code.
  3. Logging Source Generator uses global::fully.qualified.name and no usings. Json source generator looks more like code a "normal dev" would write.

We should be consistent between these source generators in what the generated code looks like. That way we don't have bugs/bad user experiences with one generator that don't apply to the other.

cc @layomia @maryamariyan

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions