dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
15.27k stars 4.73k forks source link

[API Proposal]: Introduce a feature to indicate an attribute is used to drive code generation #58994

Closed geeknoid closed 2 years ago

geeknoid commented 3 years ago

Background and motivation

Attributes are typically used to drive C# source code generation. These attributes are only necessary during the build process and don't need to bloat the final binary produced. It would be useful to have a standard way to indicate attributes are for code generation and should be omitted from the final output.

Right now, I'm using this:

    [AttributeUsage(AttributeTargets.Class)]
    [Conditional("CODE_GENERATION_ATTRIBUTES")]
    public sealed class AutoValidatorAttribute : Attribute
    {
    }

The [Conditional] attribute gets the job done, but it's clunky. A dedicated mechanism for this would be cleaner.

API Proposal

Add a new property to AttributeUsageAttribute:

public class AttributeUsageAttribute
{
    public bool ForCodeGeneration { get; set; }
}

API Usage

    [AttributeUsage(AttributeTargets.Class, ForCodeGeneration = true)]
    public sealed class AutoValidatorAttribute : Attribute
    {
    }

When the C# compiler sees this option set, it would omit the attribute from the final IL generated.

Risks

No response

ghost commented 3 years ago

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

Issue Details
### Background and motivation Attributes are typically used to drive C# source code generation. These attributes are only necessary during the build process and don't need to bloat the final binary produced. It would be useful to have a standard way to indicate attributes are for code generation and should be omitted from the final output. Right now, I'm using this: ``` [AttributeUsage(AttributeTargets.Class)] [Conditional("CODE_GENERATION_ATTRIBUTES")] public sealed class AutoValidatorAttribute : Attribute { } ``` The [Conditional] attribute gets the job done, but it's clunky. A dedicated mechanism for this would be cleaner. ### API Proposal Add a new property to AttributeUsageAttribute: ```C# public class AttributeUsageAttribute { public bool ForCodeGeneration { get; set; } } ``` ### API Usage ```C# [AttributeUsage(AttributeTargets.Class, ForCodeGeneration = true)] public sealed class AutoValidatorAttribute : Attribute { } ``` When the C# compiler sees this option set, it would omit the attribute from the final IL generated. ### Risks _No response_
Author: geeknoid
Assignees: -
Labels: `api-suggestion`, `area-System.ComponentModel.DataAnnotations`, `untriaged`
Milestone: -
roji commented 3 years ago

Is the purpose here solely to strip the attribute from end assembly IL? If so, is that in order to reduce IL size, or not expose the fact that code generation was being used for some reason?

geeknoid commented 3 years ago

Three reasons.

Attributes such as [LoggerMessage] being introduced in .NET 6 can appear hundreds of times in a full application (logging done by the app itself, logging done by all the libraries it pulls in, etc). I don't want to burden our assemblies with this needless content as it just contributes to making bigger containers which impacts our ability to scale faster in a Kubernetes environment. I know we're not talking about megabytes of data here, but every little bit helps.

Exposing such attributes to customers of my assemblies is like giving them source code or the MSBuild logic used to build the code. They are an implementation detail which I don't think belongs with the final build artifacts.

And finally, depending on where they appear, these attributes can surface in the end-user docs extracted by tools like DocFx and thus pollute the documentation with content that is completely irrelevant to the consumers of the assembly.

geeknoid commented 3 years ago

It's worth mentioning a gotcha with this suggestion.

I mentioned above the trick of using [Conditional] to make it so the attributes disappear in the final compilation. This works fine with attributes like [LoggerMessage] which are applied to partial methods, or other applications that would be applied to partial classes to get the code generator to fill in the implementation.

We have a code generator that uses attributes on interfaces. The interfaces are defined in one assembly, and consumed in another assembly. This other assembly is where the code generation actually happens. In order for the compilation of second assembly to see the attributes on the interface types, those attributes cannot be elided at compilation time.

In this case. the presence of the attributes on the interface types actually serves as documentation, telling the consume this type is suitable to be used to drive code generation.

ghost commented 3 years ago

Tagging subscribers to this area: @dotnet/area-system-runtime See info in area-owners.md if you want to be subscribed.

Issue Details
### Background and motivation Attributes are typically used to drive C# source code generation. These attributes are only necessary during the build process and don't need to bloat the final binary produced. It would be useful to have a standard way to indicate attributes are for code generation and should be omitted from the final output. Right now, I'm using this: ``` [AttributeUsage(AttributeTargets.Class)] [Conditional("CODE_GENERATION_ATTRIBUTES")] public sealed class AutoValidatorAttribute : Attribute { } ``` The [Conditional] attribute gets the job done, but it's clunky. A dedicated mechanism for this would be cleaner. ### API Proposal Add a new property to AttributeUsageAttribute: ```C# public class AttributeUsageAttribute { public bool ForCodeGeneration { get; set; } } ``` ### API Usage ```C# [AttributeUsage(AttributeTargets.Class, ForCodeGeneration = true)] public sealed class AutoValidatorAttribute : Attribute { } ``` When the C# compiler sees this option set, it would omit the attribute from the final IL generated. ### Risks _No response_
Author: geeknoid
Assignees: -
Labels: `api-suggestion`, `area-System.Runtime`, `untriaged`
Milestone: -
tannergooding commented 2 years ago

This likely needs to be driven from the Roslyn/C# side and not from the libraries side.

I'd recommended opening a proposal on dotnet/csharplang or dotnet/roslyn and seeing what the compiler team has to say. If this is a feature they want, then it can come back as an API proposal for the BCL.