From c6aac381ed74b6b121072cc1779bdc1f0436ea45 Mon Sep 17 00:00:00 2001 From: James Groom Date: Fri, 29 Mar 2024 09:56:48 +1000 Subject: [PATCH] Updated Available C# and .NET features (markdown) --- Available-C#-and-.NET-features.md | 92 +++++++++++++++++-------------- 1 file changed, 52 insertions(+), 40 deletions(-) diff --git a/Available-C#-and-.NET-features.md b/Available-C#-and-.NET-features.md index d7e2fe4..02f5b58 100644 --- a/Available-C#-and-.NET-features.md +++ b/Available-C#-and-.NET-features.md @@ -5,14 +5,15 @@ BizHawk-specific notes: - In the added "convention" column, I've used required/disallowed/encouraged/discouraged/allowed like [RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119)'s MUST / MUST NOT / SHOULD / SHOULD NOT / MAY, respectively. Unsupported is also MUST NOT (because attempting to use the feature will result in an error). - Each project's target (Framework vs. Standard) is at the top of its project file, or you can check the [project graph](https://gitlab.com/TASVideos/BizHawk/-/snippets/1886666). -Legend: -✔️ Available -⭕ Available with polyfill -❌ Not available +Legend: +✔️ Available +⭕ Available with polyfill +❌ Not available ? Unknown +Some features are marked ✔️ despite ostensibly needing a polyfill because they are enhancements to existing features and work anywhere the base feature is available—for example, `switch`ing on a `Span` requires no additional polyfill. -🔵 Availablity in .NET Framework 4.8 (`net48`) -🟢 Availablity in .NET Standard 2.0 (`netstandard2.0`) +🔵 Availability in .NET Framework 4.8 (`net48`) +🟢 Availability in .NET Standard 2.0 (`netstandard2.0`) I have not considered Framework 4.7.2 and below as there is little reason not to upgrade to Framework 4.8. I have not considered Framework 4.8.1 because it matches Framework 4.8 in terms of language features and is generally not useful. I use Standard 2.0 and not Standard 2.1 as the latter is not subsumed by Framework 4.8, rendering it useless. @@ -21,50 +22,61 @@ I use Standard 2.0 and not Standard 2.1 as the latter is not subsumed by Framewo Feature | 🔵 `net48` | 🟢 `ns2.0` | convention for main BizHawk solution --:|:-:|:-:|:-- -[enhanced `nameof`](https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-11#extended-nameof-scope) | ? | ? | unsupported -[pattern matching for `Span`](https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-11#pattern-match-spanchar-or-readonlyspanchar-on-a-constant-string) | ? | ? | unsupported -Kotlin-like [raw string literals](https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-11#raw-string-literals) | ? | ? | unsupported -[list pattern matching](https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-11#list-patterns) | ? | ? | unsupported -[multi-line expressions in interpolated strings](https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-11#newlines-in-string-interpolations) | ? | ? | unsupported -[generic maths](https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-11#generic-math-support) using [static abstract members](https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/tutorials/static-abstract-interface-methods) | ? | ? | unsupported -[genericised attributes](https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-11#generic-attributes) | ? | ? | unsupported +[`[InlineArray]`](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/struct#inline-arrays) | ❌ | ❌ | unsupported +[`using` aliases](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-directive#using-alias) for tuples, etc. | ✔️ | ✔️ | disallowed (use a struct instead of a tuple alias and we'll consider replacing them with `` later) +[default arguments for lambdas](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/lambda-expressions#input-parameters-of-a-lambda-expression) | ✔️ | ✔️ | encouraged +[`ref readonly` parameters](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/method-parameters#ref-readonly-modifier) | ✔️ | ✔️ | allowed +[unified `Span`/`Array`/`List` init syntax](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/collection-expressions) | ✔️ | ✔️ | encouraged +[primary constructors](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/instance-constructors#primary-constructors) on non-`record`s | ✔️ | ✔️ | encouraged +^ C# 12 ^ | 🔵 `net48` | 🟢 `ns2.0` | --- +[`file` access modifier](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/file) | ✔️ | ✔️ | allowed +simple [`ref` fields](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/ref-struct#ref-fields) | ❌ | ❌ | unsupported +[`required` props](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/required) | ⭕ | ⭕ | disallowed +[`Encoding.UTF8.GetBytes` shorthand](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/reference-types#utf-8-string-literals) | ✔️ | ✔️ | encouraged +[enhanced `nameof`](https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-11#extended-nameof-scope) | ✔️ | ✔️ | encouraged +[pattern matching for `Span`](https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-11#pattern-match-spanchar-or-readonlyspanchar-on-a-constant-string) | ✔️ | ✔️ | encouraged +Kotlin-like [raw string literals](https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-11#raw-string-literals) | ✔️ | ✔️ | allowed +[list pattern matching](https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-11#list-patterns) | ✔️ | ✔️ | encouraged +[multi-line expressions in interpolated strings](https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-11#newlines-in-string-interpolations) | ✔️ | ✔️ | discouraged +[generic maths](https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-11#generic-math-support) using [static abstract members](https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/tutorials/static-abstract-interface-methods) | ❌ | ❌ | unsupported +[genericised attributes](https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-11#generic-attributes) | ✔️ | ✔️ | allowed ^ C# 11 ^ | 🔵 `net48` | 🟢 `ns2.0` | --- per-method [`AsyncMethodBuilder`](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#asyncmethodbuilder-attribute) | ? | ? | unsupported -[enhanced `null` analysis](https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-10#improved-definite-assignment) | ? | ? | unsupported -[enhanced destructuring](https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-10#assignment-and-declaration-in-same-deconstruction) | ✔️ | ✔️ | unsupported -[`sealed` `ToString` in records](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/record#built-in-formatting-for-display) | ? | ? | unsupported -limited string interpolation in [consts](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/const) | ✔️ | ✔️ | unsupported -[attributes for lambdas](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/lambda-expressions#attributes) | ✔️ | ✔️ | unsupported -[type inference for lambdas](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/lambda-expressions#natural-type-of-a-lambda-expression) | ✔️ | ✔️ | unsupported -[pattern matching](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/patterns#property-pattern) IV | ✔️ | ✔️ | unsupported -[`namespace A;`](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/namespace) | ✔️ | ✔️ | unsupported -[`global using A;`](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-directive#global-modifier)/[``](https://docs.microsoft.com/en-us/dotnet/core/project-sdk/msbuild-props#using) | ✔️ | ✔️ | unsupported -[custom interpolated string handlers](https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/tutorials/interpolated-string-handler) | ? | ? | unsupported -[`with` for structs](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/with-expression) | ✔️ | ✔️ | unsupported -[enhanced struct field init](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/struct#struct-initialization-and-default-values) | ✔️ | ✔️ | unsupported -[`record struct`](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/record) | ✔️ | ✔️ | unsupported +[enhanced `null` analysis](https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-10#improved-definite-assignment) | ✔️ | ✔️ | allowed +[enhanced destructuring](https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-10#assignment-and-declaration-in-same-deconstruction) | ✔️ | ✔️ | encouraged +[`sealed` `ToString` in records](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/record#built-in-formatting-for-display) | ✔️ | ✔️ | discouraged (as per records) +limited string interpolation in [consts](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/const) | ✔️ | ✔️ | encouraged +[attributes for lambdas](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/lambda-expressions#attributes) | ✔️ | ✔️ | allowed +[type inference for lambdas](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/lambda-expressions#natural-type-of-a-lambda-expression) | ✔️ | ✔️ | allowed +[pattern matching](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/patterns#property-pattern) IV | ✔️ | ✔️ | encouraged +[`namespace A;`](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/namespace) | ✔️ | ✔️ | disallowed (will mass-migrate) +[`global using A;`](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-directive#global-modifier)/[``](https://docs.microsoft.com/en-us/dotnet/core/project-sdk/msbuild-props#using) | ✔️ | ✔️ | disallowed (will mass-migrate) +[custom interpolated string handlers](https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/tutorials/interpolated-string-handler) | ⭕ | ⭕ | allowed +[`with` for structs](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/with-expression) | ✔️ | ✔️ | allowed +[enhanced struct field init](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/struct#struct-initialization-and-default-values) | ✔️ | ✔️ | discouraged +[`record struct`](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/record) | ✔️ | ✔️ | discouraged (as per records) ^ C# 10 ^ | 🔵 `net48` | 🟢 `ns2.0` | --- -enhanced [partial methods](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/partial-method) | ? | ? | unsupported -[`[ModuleInitializer]` method](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#moduleinitializer-attribute) | ⭕ | ⭕ | unsupported +enhanced [partial methods](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/partial-method) | ✔️ | ✔️ | allowed +[`[ModuleInitializer]` method](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#moduleinitializer-attribute) | ⭕ | ⭕ | discouraged [attributes on local methods](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-9.0/local-function-attributes) | ✔️ | ✔️ | allowed [discarding](https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/functional/discards) lambda parameters | ✔️ | ✔️ | encouraged -[`foreach` picks up `GetEnumerator` extension](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-9.0/extension-getenumerator) | ✔️ | ✔️ | discouraged (surely this can only be used for stupid) +[`foreach` picks up extension `GetEnumerator`s](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-9.0/extension-getenumerator) | ✔️ | ✔️ | discouraged (surely this can only be used for stupid) [covariant return type when overriding](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-9.0/covariant-returns) | ❌ | ❌ | unsupported [enhanced type inference](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-9.0/target-typed-conditional-expression) | ✔️ | ✔️ | omit explicit type cast where possible, otherwise place the cast on default branch of `switch` and first branch of ternary [`static` lambdas](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/lambda-expressions#capture-of-outer-variables-and-variable-scope-in-lambda-expressions) | ✔️ | ✔️ | encouraged target-typed [`new()`](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/new-operator#constructor-invocation) | ✔️ | ✔️ | encouraged -[function pointers](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/unsafe-code#function-pointers) | ? | ? | unsupported -[`nint`/`nuint`](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/integral-numeric-types#native-sized-integers) | ✔️ | ✔️ | allowed +basic [function pointers](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/unsafe-code#function-pointers) | ✔️ | ✔️ | encouraged +[`nint`/`nuint` keywords](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/integral-numeric-types#native-sized-integers) | ✔️ | ✔️ | allowed [pattern matching](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/patterns#logical-patterns) III | ✔️ | ✔️ | encouraged -[unindented `Main`](https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/program-structure/top-level-statements) | ? | ? | N/A (neither executable uses it) -[`with` for records](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/with-expression) | ✔️ | ✔️ | discouraged -[`init`](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/init) | ✔️ | ✔️ | discouraged +[unindented `Main`](https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/program-structure/top-level-statements) | ✔️ | N/A | N/A (neither executable uses it) +[`with` for records](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/with-expression) | ✔️ | ✔️ | discouraged (as per records) +[`init`](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/init) | ⭕ | ⭕ | discouraged [`record class`](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/record) | ✔️ | ✔️ | discouraged ^ C# 9 ^ | 🔵 `net48` | 🟢 `ns2.0` | --- `@$""` (instead of `$@""`) | ✔️ | ✔️ | disallowed [`stackalloc`](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/stackalloc) as arg for `Span` param | ✔️ | ✔️ | allowed [`??=`](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-coalescing-operator) | ✔️ | ✔️ | encouraged -[`Index` and `Range` (`^` and `..` operators)](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/member-access-operators#index-from-end-operator-) | ⭕ | ⭕ | unsupported (we have a generic `Range` but it has some problems, like not working with `..`) +[`Index` and `Range` (`^` and `..` operators)](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/member-access-operators#index-from-end-operator-) | ⭕ | ⭕ | unsupported (we have a generic `Range>` but it has some problems, like not working with `..`) [async streams](https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/tutorials/generate-consume-asynchronous-stream) | ⭕ | ⭕ | unknown NRTs (attribute-based analysis) | ⭕ | ⭕ | encouraged NRTs (syntax and basic analysis) | ✔️ | ✔️ | encouraged for new files, see [project graph](https://gitlab.com/TASVideos/BizHawk/-/snippets/1886666) for when `#nullable enable` is needed @@ -78,19 +90,19 @@ static [local methods](https://docs.microsoft.com/en-us/dotnet/csharp/programmin `field` [attribute target](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/attributes/#attribute-targets) for auto-prop backing field | ✔️ | ✔️ | discouraged (surely this can only be used for stupid) [`stackalloc`](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/stackalloc) with array intialiser | ✔️ | ✔️ | encouraged ^ C# 7.3 ^ | 🔵 `net48` | 🟢 `ns2.0` | --- -[`Span`](https://docs.microsoft.com/en-us/dotnet/standard/memory-and-spans/) and co. | ⭕ | ⭕ | allowed +[`Span`](https://docs.microsoft.com/en-us/dotnet/standard/memory-and-spans/) and co. | ⭕ | ⭕ | encouraged [`ref struct`](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/struct#ref-struct) (stack-bound) | ✔️ | ✔️ | allowed [`readonly struct`](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/struct#readonly-struct) and `in` parameters | ✔️ | ✔️ | encouraged ^ C# 7.2 ^ | 🔵 `net48` | 🟢 `ns2.0` | --- [inferred tuple field names](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/value-tuples#tuple-field-names) | ✔️ | ✔️ | discouraged -[`default` without type](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/default#default-literal) | ✔️ | ✔️ | encouraged for non-nullable value types, discouraged otherwise +[`default` without type](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/default#default-literal) | ✔️ | ✔️ | encouraged for non-nullable value types, or as `default!` to appease compiler when definitely assigned, discouraged otherwise [`async` `Main`](https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/program-structure/main-command-line#async-main-return-values) | ? | ? | N/A (neither executable uses it) ^ C# 7.1 ^ | 🔵 `net48` | 🟢 `ns2.0` | --- [`throw` expression](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/throw#the-throw-expression) | ✔️ | ✔️ | encouraged [enhanced int literals](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/integral-numeric-types#integer-literals) | ✔️ | ✔️ | encouraged [discards](https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/functional/discards) | ✔️ | ✔️ | encouraged [`ref` returns/locals](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/ref-returns) | ✔️ | ✔️ | allowed -[expression-bodied ctors](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/expression-bodied-members#constructors) | ✔️ | ✔️ | encouraged +[expression-bodied constructors](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/expression-bodied-members#constructors) | ✔️ | ✔️ | encouraged [local methods](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/local-functions) | ✔️ | ✔️ | preferred over lambdas/delegates if used multiple times or to unsub from event basic [pattern matching](https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/functional/pattern-matching) | ✔️ | ✔️ | encouraged [`KeyValuePair.Deconstruct`](https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.keyvaluepair-2.deconstruct?view=net-6.0) | ⭕ | ⭕ | allowed @@ -110,11 +122,11 @@ inline initialisation of [auto-props](https://docs.microsoft.com/en-us/dotnet/cs ^ C# 5 ^ | 🔵 `net48` | 🟢 `ns2.0` | --- [covariant and contravariant generics](https://docs.microsoft.com/en-us/dotnet/standard/generics/covariance-and-contravariance) | ✔️ | ✔️ | encouraged [default arguments](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments#optional-arguments) | ✔️ | ✔️ | preferred over overloads -[named arguments](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments#named-arguments) | ✔️ | ✔️ | encouraged for primitive-typed parameters +[named arguments](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments#named-arguments) | ✔️ | ✔️ | encouraged for primitive-typed parameters or when 2+ parameters are of the same type [`dynamic` type](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/types/using-type-dynamic) | ✔️ | ⭕ | discouraged ^ C# 4 ^ | 🔵 `net48` | 🟢 `ns2.0` | --- [object initialisation syntax](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/object-and-collection-initializers) | ✔️ | ✔️ | encouraged -[partial methods](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/partial-method) | ✔️ | ✔️ | allowed +simple [partial methods](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/partial-method) | ✔️ | ✔️ | allowed [`var`](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/var) | ✔️ | ✔️ | preferred except when target-typed `new()` can be used [extension methods](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods) | ✔️ | ✔️ | allowed [`Expression` trees](https://docs.microsoft.com/en-us/dotnet/csharp/expression-trees) | ✔️ | ✔️ | discouraged (what are these even for)