From f8a35e5652ffaa83e15c0b70bcb61c47b68c9e97 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Tue, 3 Sep 2024 19:37:13 -0400 Subject: [PATCH] Update attributes language reference --- .../language-reference/attributes/general.md | 15 +++++++++++ .../attributes/snippets/OrpaSnippets.cs | 25 +++++++++++++++++++ .../attributes/snippets/Program.cs | 3 +++ .../attributes/snippets/attributes.csproj | 2 +- 4 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 docs/csharp/language-reference/attributes/snippets/OrpaSnippets.cs diff --git a/docs/csharp/language-reference/attributes/general.md b/docs/csharp/language-reference/attributes/general.md index c3ea4dace702b..db2d42306e124 100644 --- a/docs/csharp/language-reference/attributes/general.md +++ b/docs/csharp/language-reference/attributes/general.md @@ -15,6 +15,7 @@ There are several attributes that can be applied to elements in your code that a - [`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. The compiler uses those semantic meanings to alter its output and report possible mistakes by developers using your code. @@ -229,6 +230,20 @@ You add this attribute where the compiler treats a `ref` as implicitly `scoped`: Applying the marks the element as unscoped. +## `OverloadResolutionPriority` attribute + +The enables library authors to prefer one overload over another when two overloads can be ambiguous. Its primary use case is for library authors to write better performing overloads while still supporting existing code without breaks. + +For example, you might add a new overload that uses to reduce memory allocations: + +:::code language="csharp" source="snippets/OrpaExample.cs" ID="SnippetOverloadExample"::: + +Overload resolution considers the two methods equally good for some argument types. For an argument of `int[]`, it prefers the first overload. To get the compiler to prefer the `ReadOnlySpan` version, you can increase the priority of that overload. The following example show the effect of adding the attribute: + +:::code language="csharp" source="snippets/OrpaExample.cs" ID="SnippetOrpaExample"::: + +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/overload-resolution-priority.md#overload-resolution-priority) impacts choosing the better method. Otherwise, unexpected errors can result. + ## See also - diff --git a/docs/csharp/language-reference/attributes/snippets/OrpaSnippets.cs b/docs/csharp/language-reference/attributes/snippets/OrpaSnippets.cs new file mode 100644 index 0000000000000..1031c2a283da6 --- /dev/null +++ b/docs/csharp/language-reference/attributes/snippets/OrpaSnippets.cs @@ -0,0 +1,25 @@ +using System.Runtime.CompilerServices; + +namespace attributes; +public class OverloadExample +{ + + public static void OrpaExample() + { + // + var d = new OverloadExample(); + int[] arr = [1, 2, 3]; + d.M(1, 2, 3, 4); // Prints "Span" + d.M(arr); // Prints "Span" when PriorityAttribute is applied + d.M([1, 2, 3, 4]); // Prints "Span" + d.M(1, 2, 3, 4); // Prints "Span" + // + } + + // + [OverloadResolutionPriority(1)] + public void M(params ReadOnlySpan s) => Console.WriteLine("Span"); + // Default overload resolution priority of 0 + public void M(params int[] a) => Console.WriteLine("Array"); + // +} diff --git a/docs/csharp/language-reference/attributes/snippets/Program.cs b/docs/csharp/language-reference/attributes/snippets/Program.cs index 0ff8c36ffd728..db6e80a303e71 100644 --- a/docs/csharp/language-reference/attributes/snippets/Program.cs +++ b/docs/csharp/language-reference/attributes/snippets/Program.cs @@ -1,6 +1,9 @@ using attributes; using AttributeExamples; + +OverloadExample.OrpaExample(); + TraceExample.Main(); ObsoleteProgram.Main(); ModuleInitializerExampleMain.Main(); diff --git a/docs/csharp/language-reference/attributes/snippets/attributes.csproj b/docs/csharp/language-reference/attributes/snippets/attributes.csproj index 1cc17f97a2736..0e8ab5607efbd 100644 --- a/docs/csharp/language-reference/attributes/snippets/attributes.csproj +++ b/docs/csharp/language-reference/attributes/snippets/attributes.csproj @@ -2,7 +2,7 @@ Exe - net8.0 + net9.0 enable true enable