Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
eerhardt opened this issue May 4, 2021 · 3 comments
Assignees
Milestone

Comments

@eerhardt
Copy link
Member

eerhardt commented May 4, 2021

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

@ghost ghost added area-System.Text.Json untriaged New issue has not been triaged by the area owner labels May 4, 2021
@ghost
Copy link

ghost commented May 4, 2021

Tagging subscribers to this area: @eiriktsarpalis, @layomia
See info in area-owners.md if you want to be subscribed.

Issue Details
Author: eerhardt
Assignees: -
Labels:

area-System.Text.Json, untriaged

Milestone: -

@layomia layomia removed the untriaged New issue has not been triaged by the area owner label May 12, 2021
@layomia layomia self-assigned this May 12, 2021
@layomia layomia added this to the 6.0.0 milestone May 12, 2021
@layomia
Copy link
Contributor

layomia commented May 27, 2021

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

The PR #53212 has addressed all of these, except having #nullable enable at the top of each file.

@layomia
Copy link
Contributor

layomia commented Aug 9, 2021

All issues here have been addressed, except for nullability which is tracked by #52227.

@layomia layomia closed this as completed Aug 9, 2021
@ghost ghost locked as resolved and limited conversation to collaborators Sep 8, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants