0 Available C# and .NET features
YoshiRulz edited this page 2024-12-16 23:21:16 +10:00
This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This document is to supplement BizHawk development, and will be deleted once the project is on .NET Core. Yoshi will maintain a copy on GitLab for the benefit of other projects.

BizHawk-specific notes:

  • All projects in /src use C# 12 currently, as do all the .NET projects in /External*Projects but new features have only been adopted in the main solution.
  • In the added "convention" column, I've used required/disallowed/encouraged/discouraged/allowed like RFC 2119'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.

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, switching on a Span<char> requires no additional polyfill.
The official BCL type reference now has a "netstandard2.0 w/ polyfills" filter, though it obviously won't have third-party polyfills.

🔵 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.

Note: .NET calls destructuring "deconstructing", not to be confused with destructing which .NET calls "finalising".

Feature 🔵 net48 🟢 ns2.0 convention for main BizHawk solution
prop backing field as field ✔️ ✔️ waiting for .NET 10 LTS
^ C# 14 ^ 🔵 net48 🟢 ns2.0 ---
partial props/indexers ✔️ ✔️ waiting for .NET 10 LTS
allows ref struct constraint unsupported
interfaces for ref structs ✔️ ✔️ discouraged (very useless)
ref structs and unsafe in state-machine methods ? ? presumably unsupported
escape sequence for ␛ char ✔️ ✔️ waiting for .NET 10 LTS
sugar for lock with Lock should be able to use polyfill w/ C# 12
enhanced params ✔️ ✔️ waiting for .NET 10 LTS
^ C# 13 ^ 🔵 net48 🟢 ns2.0 ---
[UnsafeAccessor] unsupported
[InlineArray] unsupported
using aliases for tuples, etc. ✔️ ✔️ disallowed (use a struct instead of a tuple alias and we'll consider replacing them with <Using/> later)
default arguments for lambdas ✔️ ✔️ discouraged (you should be using local methods)
ref readonly parameters ✔️ ✔️ allowed
unified Span/Array/List init syntax ✔️ ✔️ encouraged
primary constructors on non-records ✔️ ✔️ encouraged
^ C# 12 ^ 🔵 net48 🟢 ns2.0 ---
file access modifier ✔️ ✔️ allowed
simple ref fields unsupported
required props disallowed
Encoding.UTF8.GetBytes shorthand ✔️ ✔️ encouraged
enhanced nameof ✔️ ✔️ encouraged
pattern matching for Span<char> ✔️ ✔️ encouraged
Kotlin-like raw string literals ✔️ ✔️ allowed
list pattern matching ✔️ ✔️ encouraged
multi-line expressions in interpolated strings ✔️ ✔️ discouraged
generic maths using static abstract members unsupported
genericised attributes ✔️ ✔️ allowed
^ C# 11 ^ 🔵 net48 🟢 ns2.0 ---
per-method AsyncMethodBuilder ? ? unsupported
enhanced null analysis ✔️ ✔️ allowed
enhanced destructuring ✔️ ✔️ encouraged
sealed ToString in records ✔️ ✔️ encouraged when records are used
limited string interpolation in consts ✔️ ✔️ encouraged
attributes for lambdas ✔️ ✔️ allowed
type inference for lambdas ✔️ ✔️ allowed
pattern matching IV ✔️ ✔️ encouraged
namespace A; ✔️ ✔️ disallowed (will mass-migrate)
global using A;/<Using> ✔️ ✔️ disallowed (will mass-migrate)
custom interpolated string handlers allowed
with for structs ✔️ ✔️ allowed
enhanced struct field init ✔️ ✔️ discouraged
record struct ✔️ ✔️ discouraged
^ C# 10 ^ 🔵 net48 🟢 ns2.0 ---
enhanced partial methods ✔️ ✔️ allowed
[ModuleInitializer] method discouraged
attributes on local methods ✔️ ✔️ allowed
discarding lambda parameters ✔️ ✔️ encouraged
foreach picks up extension GetEnumerators ✔️ ✔️ discouraged (surely this can only be used for stupid)
covariant return type when overriding unsupported
enhanced type inference ✔️ ✔️ omit explicit type cast where possible, otherwise place the cast on default branch of switch and first branch of ternary
static lambdas ✔️ ✔️ encouraged
target-typed new() ✔️ ✔️ encouraged
basic function pointers ✔️ ✔️ encouraged
nint/nuint keywords ✔️ ✔️ allowed
pattern matching III ✔️ ✔️ encouraged
unindented Main ✔️ N/A N/A (neither executable uses it)
with for records ✔️ ✔️ encouraged when records are used
init discouraged
record class ✔️ ✔️ discouraged
^ C# 9 ^ 🔵 net48 🟢 ns2.0 ---
@$"" (instead of $@"") ✔️ ✔️ disallowed
stackalloc as arg for Span param ✔️ ✔️ allowed
??= ✔️ ✔️ encouraged
Index and Range (^ and .. operators) discouraged (we also have a generic Range<T: unmanaged, IComparable<T>> but it has some problems, like not working with ..)
async streams unknown
NRTs (attribute-based analysis) encouraged
NRTs (syntax and basic analysis) ✔️ ✔️ encouraged for new files, see project graph for when #nullable enable is needed
static local methods ✔️ ✔️ encouraged
using statement without block ✔️ ✔️ encouraged
pattern matching II ✔️ ✔️ encouraged
switch expression ✔️ ✔️ encouraged
default interface methods unsupported
readonly methods/getters/setters ✔️ ✔️ encouraged
^ C# 8 ^ 🔵 net48 🟢 ns2.0 ---
field attribute target for auto-prop backing field ✔️ ✔️ discouraged (surely this can only be used for stupid)
stackalloc with array intialiser ✔️ ✔️ encouraged
^ C# 7.3 ^ 🔵 net48 🟢 ns2.0 ---
Span and co. encouraged
ref struct (stack-bound) ✔️ ✔️ allowed
readonly struct and in parameters ✔️ ✔️ encouraged
^ C# 7.2 ^ 🔵 net48 🟢 ns2.0 ---
inferred tuple field names ✔️ ✔️ discouraged
default without type ✔️ ✔️ encouraged for non-nullable value types, or as default! to appease compiler when definitely assigned, discouraged otherwise
async Main ? ? N/A (neither executable uses it)
^ C# 7.1 ^ 🔵 net48 🟢 ns2.0 ---
throw expression ✔️ ✔️ encouraged
enhanced int literals ✔️ ✔️ encouraged
discards ✔️ ✔️ encouraged
ref returns/locals ✔️ ✔️ allowed
expression-bodied constructors ✔️ ✔️ encouraged
local methods ✔️ ✔️ preferred over lambdas/delegates if used multiple times or to unsub from event
basic pattern matching ✔️ ✔️ encouraged
KeyValuePair<K, V>.Deconstruct allowed
basic tuples and destructuring ✔️ ✔️ encouraged
out var ✔️ ✔️ encouraged
^ C# 7.0 ^ 🔵 net48 🟢 ns2.0 ---
nameof ✔️ ✔️ encouraged
interpolated string literals ✔️ ✔️ preferred over string.Format or concatenation
null-conditional member access ✔️ ✔️ required
expression-bodied methods/props ✔️ ✔️ encouraged
inline initialisation of auto-props ✔️ ✔️ encouraged
catch (Exception e) when (predicate(e)) ✔️ ✔️ encouraged
using static A; ✔️ ✔️ allowed only for the file's own namespace
^ C# 6 ^ 🔵 net48 🟢 ns2.0 ---
[Caller*] ✔️ ✔️ allowed
async ✔️ ✔️ allowed
^ C# 5 ^ 🔵 net48 🟢 ns2.0 ---
covariant and contravariant generics ✔️ ✔️ encouraged
default arguments ✔️ ✔️ preferred over overloads
named arguments ✔️ ✔️ encouraged for primitive-typed parameters or when 2+ parameters are of the same type
dynamic type ✔️ discouraged
^ C# 4 ^ 🔵 net48 🟢 ns2.0 ---
object initialisation syntax ✔️ ✔️ encouraged
simple partial methods ✔️ ✔️ allowed
var ✔️ ✔️ preferred except when target-typed new() can be used
extension methods ✔️ ✔️ allowed
Expression trees ✔️ ✔️ discouraged (what are these even for)
lambdas ✔️ ✔️ preferred over delegates
LINQ's query expression syntax ✔️ ✔️ disallowed
anonymous classes ✔️ ✔️ disallowed (use tuples)
auto-props ✔️ ✔️ encouraged
^ C# 3 ^ 🔵 net48 🟢 ns2.0 ---
anonymous delegates ✔️ ✔️ disallowed
^ C# 2 ^ 🔵 net48 🟢 ns2.0 ---
using alias ✔️ ✔️ discouraged unless there's a conflict
delegate constructors ✔️ ✔️ disallowed
unsafe (pointers etc.) ✔️ ✔️ discouraged

The official C# version history is here, with this separate list for vNext.