Skip to content

Clean edit pass on attributes #44513

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

Merged
merged 11 commits into from
Jan 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 33 additions & 6 deletions docs/csharp/language-reference/attributes/general.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
---
title: "Attributes interpreted by the compiler: Miscellaneous"
ms.date: 11/22/2024
ms.date: 01/24/2025
description: "Learn about attributes that affect code generated by the compiler: the Conditional, Obsolete, AttributeUsage, ModuleInitializer, and SkipLocalsInit attributes."
---
# Miscellaneous attributes interpreted by the C# compiler

There are several attributes that can be applied to elements in your code that add semantic meaning to those elements:

- [`Conditional`](#conditional-attribute): Make execution of a method dependent on a preprocessor identifier.
- [`Obsolete`](#obsolete-attribute): Mark a type or member for (potential) future removal.
- [`Obsolete`](#obsolete-and-deprecated-attribute): Mark a type or member for (potential) future removal.
- [`Deprecated`](#obsolete-and-deprecated-attribute): (Windows Foundation) Mark a type or member for (potential) future removal.
- [`Experimental`](#experimental-attributes): Mark a type or member as experimental.
- [`SetsRequiredMembers`](#setsrequiredmembers-attribute): Indicate that a constructor sets all required properties.
- [`AttributeUsage`](#attributeusage-attribute): Declare the language elements where an attribute can be applied.
- [`AsyncMethodBuilder`](#asyncmethodbuilder-attribute): Declare an async method builder type.
- [`InterpolatedStringHandler`](#interpolatedstringhandler-and-interpolatedstringhandlerarguments-attributes): Define an interpolated string builder for a known scenario.
- [`ModuleInitializer`](#moduleinitializer-attribute): Declare a method that initializes a module.
- [`SkipLocalsInit`](#skiplocalsinit-attribute): Elide the code that initializes local variable storage to 0.
- [`UnscopedRef`](#unscopedref-attribute): Declare that a `ref` variable normally interpreted as `scoped` should be treated as unscoped.
- [`OverloadResolutionPriority`](#overloadresolutionpriority-attribute): Add a tiebreaker attribute to influence overload resolution for possibly ambiguous overloads.
- [`Experimental`](#experimental-attribute): Mark a type or member as experimental.
- [`EnumeratorCancellation`](#enumeratorcancellation-attribute): Specify the parameter for a cancellation token in an async enumerator.
- [`CollectionBuilder`](#collectionbuilder-attribute): Specify the builder method for a collection type when a collection expression is converted to that collection type.
- [`InlineArray`](#inlinearray-attribute): Specify that a `struct` type is an *inline array*.
- [`IUnknownConstant`](#iunknownconstant-and-idispatchconstant-attributes): Specifies how a missing argument should be supplied for a default parameter.
- [`IDispatchConstant`](#iunknownconstant-and-idispatchconstant-attributes): Specifies how a missing argument should be supplied for a default parameter.

The compiler uses those semantic meanings to alter its output and report possible mistakes by developers using your code.

Expand Down Expand Up @@ -46,7 +53,7 @@ The `Conditional` attribute can also be applied to an attribute class definition

:::code language="csharp" source="snippets/ConditionalExamples.cs" ID="SnippetConditionalConditionalAttribute" :::

## `Obsolete` attribute
## `Obsolete` and `Deprecated` attribute

The `Obsolete` attribute marks a code element as no longer recommended for use. Use of an entity marked obsolete generates a warning or an error. The `Obsolete` attribute is a single-use attribute and can be applied to any entity that allows attributes. `Obsolete` is an alias for <xref:System.ObsoleteAttribute>.

Expand All @@ -58,15 +65,19 @@ The string provided as the first argument to the attribute constructor is displa

:::code language="csharp" source="snippets/ObsoleteExample.cs" id="Snippet2" :::

## `Experimental` attribute
The Windows Foundation Metadata libraries use the <xref:Windows.Foundation.Metadata.DeprecatedAttribute?displayProperty=nameWithType> instead of the `ObsoleteAttribute`.

## `Experimental` attributes

Beginning in C# 12, types, methods, and assemblies can be marked with the <xref:System.Diagnostics.CodeAnalysis.ExperimentalAttribute?displayProperty=nameWithType> to indicate an experimental feature. The compiler issues a warning if you access a method or type annotated with the <xref:System.Diagnostics.CodeAnalysis.ExperimentalAttribute>. All types declared in an assembly or module marked with the `Experimental` attribute are experimental. The compiler issues a warning if you access any of them. You can disable these warnings to pilot an experimental feature.

> [!WARNING]
> Experimental features are subject to changes. The APIs may change, or they may be removed in future updates. Including experimental features is a way for library authors to get feedback on ideas and concepts for future development. Use extreme caution when using any feature marked as experimental.
> Experimental features are subject to changes. The APIs can change, or they can be removed in future updates. Including experimental features is a way for library authors to get feedback on ideas and concepts for future development. Use extreme caution when using any feature marked as experimental. You can learn more about how APIs are marked as experimental in our article on [preview APIs](../../../fundamentals/runtime-libraries/preview-apis.md#experimentalattribute).

You can read more details about the `Experimental` attribute in the [feature specification](~/_csharplang/proposals/csharp-12.0/experimental-attribute.md).

The Windows Foundation Metadata libraries use the <xref:Windows.Foundation.Metadata.ExperimentalAttribute?displayProperty=nameWithType>, which predates C# 12.

## `SetsRequiredMembers` attribute

The `SetsRequiredMembers` attribute informs the compiler that a constructor sets all `required` members in that class or struct. The compiler assumes any constructor with the <xref:System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute?displayProperty=fullName> attribute initializes all `required` members. Any code that invokes such a constructor doesn't need object initializers to set required members. Adding the `SetsRequiredMembers` attribute is primarily useful for positional records and primary constructors.
Expand Down Expand Up @@ -242,6 +253,22 @@ Overload resolution considers the two methods equally good for some argument typ

All overloads with a lower priority than the highest overload priority are removed from the set of applicable methods. Methods without this attribute have the overload priority set to the default of zero. Library authors should use this attribute as a last resort when adding a new and better method overload. Library authors should have a deep understanding of how [Overload resolution](~/_csharplang/proposals/csharp-13.0/overload-resolution-priority.md#overload-resolution-priority) impacts choosing the better method. Otherwise, unexpected errors can result.

## EnumeratorCancellation attribute

The <xref:System.Runtime.CompilerServices.EnumeratorCancellationAttribute?displayProperty=nameWithType> attribute specifies which parameter should receive the cancellation token from the <xref:System.Collections.Generic.IAsyncEnumerable`1.GetAsyncEnumerator(System.Threading.CancellationToken)?displayProperty=fullName> API. It's part of the infrastructure for the [async streams](../../asynchronous-programming/generate-consume-asynchronous-stream.md) feature.

## CollectionBuilder attribute

The <xref:System.Runtime.CompilerServices.CollectionBuilderAttribute?displayProperty=nameWithType> attribute specifies a method that builds an instance of a collection type from a [collection expression](../operators/collection-expressions.md). You use this attribute to specify a method that builds the collection. The compiler generates code to call that method when a collection expression is converted to that type.

## InlineArray attribute

The <xref:System.Runtime.CompilerServices.InlineArrayAttribute?displayProperty=nameWithType> attribute marks a type as an [inline array](../builtin-types/struct.md#inline-arrays). You can learn more about this feature in the article on `structs`, in the section on [inline arrays](../builtin-types/struct.md#inline-arrays).

## IUnknownConstant and IDispatchConstant attributes

The <xref:System.Runtime.CompilerServices.IUnknownConstantAttribute?displayProperty=nameWithType> and <xref:System.Runtime.CompilerServices.IDispatchConstantAttribute?displayProperty=nameWithType> attributes can be added to default parameters to indicate that a missing argument should be supplied as `new UnknownWrapper(null)` or `new DispatchWrapper(null)`.

## See also

- <xref:System.Attribute>
Expand Down
55 changes: 55 additions & 0 deletions docs/csharp/language-reference/attributes/pseudo-attributes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
---
title: "Attributes interpreted by the compiler: Pseudo-attributes"
ms.date: 01/2/2025
description: "Learn about attributes you can add to code that are written to IL as modifiers. These custom attributes aren't emitted as attributes in the compiled output."
---
# Custom attributes that generate flags or options in the Intermediate Language (IL) output

You add these attributes to your code for the compiler to emit a specified Intermediate Language (IL) modifier. These attributes instruct the compiler to include the corresponding IL modifier in the output.

| Attribute | Modifier | Comments |
|--------------------------------------------------------------------------------------|-----------------|-----------|
| <xref:System.Runtime.InteropServices.ComImportAttribute?displayProperty=fullName> | `import` | |
| <xref:System.Runtime.InteropServices.DllImportAttribute?displayProperty=fullName> | `pinvokeimpl` | You can add options listed in the constructor. |
| <xref:System.Runtime.InteropServices.FieldOffsetAttribute?displayProperty=fullName> | `.field` | This sets the field offset for memory layout. |
| <xref:System.Runtime.InteropServices.MarshalAsAttribute> | `marshal` | You can set options listed in the constructor. |
| <xref:System.Runtime.CompilerServices.MethodImplAttribute?displayProperty=fullName> | `flag` | Constructor arguments specify specific named flags such as `aggressiveinlining` or `forwardref`. These flags also specify the `native`, `managed`, or `optil` modifiers for the <xref:System.Runtime.CompilerServices.MethodCodeType?displayProperty=fullName> field. |
| <xref:System.NonSerializedAttribute?displayProperty=fullName> | `notserialized` | |
| <xref:System.Runtime.InteropServices.OptionalAttribute?displayProperty=fullName> | `[opt]` | |
| <xref:System.Runtime.InteropServices.OutAttribute?displayProperty=fullName> | `[out]` | |
Copy link
Contributor

@jnm2 jnm2 Jan 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one could have a note parallel to the note added for InAttribute, saying "Use the out modifier."

| <xref:System.Runtime.InteropServices.PreserveSigAttribute?displayProperty=fullName> | `preservesig` | |
| <xref:System.SerializableAttribute?displayProperty=fullName> | `serializable` | |
| <xref:System.Runtime.InteropServices.StructLayoutAttribute?displayProperty=fullName> | `auto`, `sequential`, or `explicit` | Layout options can be set using the parameters. |
| <xref:System.Runtime.CompilerServices.IndexerNameAttribute?displayProperty=fullName> | | You add this attribute to an indexer to set a different method name. By default, indexers are compiled to a property named `Item`. You can specify a different name using this attribute. |

Some of these custom attributes are applied using other C# syntax rather than adding the attribute to your source code.

| Attribute | Comments |
|--------------------------------------------------------------------------------------------------|----------|
| <xref:System.Runtime.InteropServices.DefaultParameterValueAttribute?displayProperty=fullName> | Specifies the default value for the parameter. Use the [default parameter syntax](../../methods.md#optional-parameters-and-arguments). |
| <xref:System.Runtime.InteropServices.InAttribute?displayProperty=fullName> | Specifies the IL `[in]` modifier. Use the [`in`](../keywords/method-parameters.md#in-parameter-modifier) or [`ref readonly`](../keywords/method-parameters.md#ref-readonly-modifier). |
| <xref:System.Runtime.CompilerServices.SpecialNameAttribute?displayProperty=fullName> | Specifies the IL `specialname` modifier. The compiler automatically adds this modifier for methods that require it. |
| <xref:System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute?displayProperty=nameWithType> | This attribute is required for the `delegate*` feature. The compiler adds it to any [`delegate*`](../unsafe-code.md#function-pointers) that requires its use. |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[UnmanagedCallersOnly] is actually something the user must apply in code in order to use the unmanaged calling convention specifically with the delegate* feature:

using System.Runtime.InteropServices;

unsafe
{
    delegate* unmanaged<void> someFuncPointer = &SomeMethod;
}

[UnmanagedCallersOnly] // Compilation fails if this is removed
static void SomeMethod() { }


The following custom attributes are generally disallowed in C# source. They're listed here to aid library authors who use reflection, and to ensure you don't create custom attributes with the same name.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though, creating custom attributes with the same name in a different namespace is okay, and custom attributes don't go in the System namespace.


| Attribute | Comments |
|--------------------------------------------------------------------------------------------------|---------|
| <xref:System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute?displayProperty=fullName> | Prevents downlevel compilers from using metadata it can't safely understand. |
| <xref:System.Runtime.CompilerServices.DecimalConstantAttribute?displayProperty=fullName> | Encodes `const decimal` fields. The runtime doesn't support `decimal` values as constant values. |
| <xref:System.Reflection.DefaultMemberAttribute?displayProperty=fullName> | Encodes indexers with <xref:System.Runtime.CompilerServices.IndexerNameAttribute?displayProperty=fullName>. This attribute notes the default indexer when its name is different than `Item`. This attribute is allowed in source. |
| <xref:System.Runtime.CompilerServices.DynamicAttribute?displayProperty=fullName> | Encodes whether a type in a signature is `dynamic` (versus `object`). |
| <xref:System.Runtime.CompilerServices.ExtensionAttribute?displayProperty=fullName> | This attribute notes extension methods. The compiler also places this attribute on the containing classes. |
| <xref:System.Runtime.CompilerServices.FixedBufferAttribute?displayProperty=fullName> | This attribute specifies `fixed` struct fields. |
| <xref:System.Runtime.CompilerServices.IsByRefLikeAttribute?displayProperty=fullName> | This attribute specifies a `ref` struct. |
| <xref:System.Runtime.CompilerServices.IsReadOnlyAttribute?displayProperty=fullName> | This attribute indicates that a parameter has the `in` modifier. It distinguishes `in` parameters from `readonly ref` or `[In] ref`. |
| <xref:System.Runtime.CompilerServices.RequiresLocationAttribute?displayProperty=fullName> | This attribute indicates that a parameter has the `readonly ref` modifier. It distinguishes `readonly ref` from `in` or `[In] ref`. |
| <xref:System.Runtime.CompilerServices.IsUnmanagedAttribute?displayProperty=fullName> | This attribute specifies the `unmanaged` constraint on a type parameter. |
| <xref:System.Runtime.CompilerServices.NullableAttribute?displayProperty=fullName>, <xref:System.Runtime.CompilerServices.NullableContextAttribute?displayProperty=fullName>, <xref:System.Runtime.CompilerServices.NullablePublicOnlyAttribute?displayProperty=fullName> | These attributes encode nullable annotations in your source code. |
| <xref:System.ParamArrayAttribute?displayProperty=fullName> | This attribute encodes the `params` modifier on array parameters. |
| <xref:System.Runtime.CompilerServices.ParamCollectionAttribute?displayProperty=fullName> | This attribute encodes the `params` modifier on non-array parameters. |
| <xref:System.Runtime.CompilerServices.RefSafetyRulesAttribute?displayProperty=fullName> | This attribute specifies the C# version that is required in order to understand ref safety annotations in the assembly. Ref safety rules evolve as C# gets new features. |
| <xref:System.Runtime.CompilerServices.RequiredMemberAttribute?displayProperty=fullName> | This attribute indicates that the `required` modifier was placed on a member declaration. It's the encoding of the [required members](../keywords/required.md) language feature. |
| <xref:System.Runtime.CompilerServices.TupleElementNamesAttribute?displayProperty=fullName> | This attribute encodes tuple element names used in signatures. |

In addition, the compiler can generate a declaration for other attributes used internally. The compiler generates these in the <xref:System.Runtime.CompilerServices> namespace for its own use. Some aren't in the .NET Runtime libraries. Instead, the compiler synthesizes a definition for an `internal` type declaration in any assembly where the attribute is needed.
26 changes: 22 additions & 4 deletions docs/csharp/language-reference/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -380,17 +380,35 @@ items:
- name: Attributes read by the compiler
items:
- name: Global attributes
displayName: AssemblyName, AssemblyVersion, AssemblyCulture, AssemblyFlags, AssemblyProduct, AssemblyTrademark, AssemblyInformationalVersion, AssemblyCompany, AssemblyCopyright, AssemblyFileVersion, CLSCompliant, AssemblyTitle, AssemblyDescription, AssemblyConfiguration, AssemblyDefaultAlias
displayName: >
AssemblyName, AssemblyVersion, AssemblyCulture, AssemblyFlags, AssemblyProduct, AssemblyTrademark, AssemblyInformationalVersion,
AssemblyCompany, AssemblyCopyright, AssemblyFileVersion, CLSCompliant, AssemblyTitle, AssemblyDescription, AssemblyConfiguration,
AssemblyDefaultAlias
href: ./attributes/global.md
- name: Caller information
displayName: CallerFilePath, CallerLineNumber, CallerMemberName
displayName: CallerFilePath, CallerLineNumber, CallerMemberName, CallerArgumentExpressionAttribute
href: ./attributes/caller-information.md
- name: Nullable static analysis
displayName: AllowNull, DisallowNull, MaybeNull, NotNull, MaybeNullWhen, NotNullWhen, NotNullIfNotNull, DoesNotReturn, DoesNotReturnIf
displayName: >
AllowNull, DisallowNull, MaybeNull, NotNull, MaybeNullWhen, NotNullWhen, NotNullIfNotNull, MemberNotNull, MemberNotNullIf,
DoesNotReturn, DoesNotReturnIf
href: ./attributes/nullable-analysis.md
- name: Miscellaneous
displayName: Conditional, Obsolete, Experimental, SetsRequiredMembers, AttributeUsage, ModuleInitializer, SkipLocalsInit, module initializer
displayName: >
Conditional, Obsolete, Deprecated, Experimental, SetsRequiredMembers, AttributeUsage, AsyncMethodBuilder, InterpolatedStringHandler,
ModuleInitializer, SkipLocalsInit, UnscopedRef, OverloadResolutionPriority. EnumeratorCancellation, CollectionBuilder,
IUnknownConstant, IDispatchConstant, module initializer
href: ./attributes/general.md
- name: Pseudo-attributes
displayName: >
ComImportAttribute, DllImportAttribute, FieldOffsetAttribute, MarshalAsAttribute, MethodImplAttribute, NonSerializedAttribute,
OptionalAttribute, OutAttribute, PreserveSigAttribute, SerializableAttribute, StructLayoutAttribute, IndexerNameAttribute,
DefaultParameterValueAttribute, InAttribute, SpecialNameAttribute, UnmanagedCallersOnlyAttribute, CompilerFeatureRequiredAttribute,
DecimalConstantAttribute, DefaultMemberAttribute, DynamicAttribute, ExtensionAttribute, FixedBufferAttribute, IsByRefLikeAttribute,
IsReadOnlyAttribute, RequiresLocationAttribute, IsUnmanagedAttribute, NullableAttribute, NullableContextAttribute,
NullablePublicOnlyAttribute, ParamArrayAttribute, ParamCollectionAttribute, RefSafetyRulesAttribute, RequiredMemberAttribute,
TupleElementNamesAttribute
href: ./attributes/pseudo-attributes.md
- name: Unsafe code and pointers
displayName: unsafe code, pointers, fixed size buffer, function pointer
href: ./unsafe-code.md
Expand Down
Loading
Loading