-
Notifications
You must be signed in to change notification settings - Fork 430
Available C# and .NET features
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
/srcuse C# 12 currently, as do all the .NET projects in/External*Projectsbut 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.
🔵 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 |
|---|---|---|---|
[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 |
✔️ | ✔️ | discouraged (as per records) |
| 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 (as per records) |
| ^ 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 |
✔️ | ✔️ | discouraged (as per records) |
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 |
Seen something on this wiki page that can be improved? Only repo members can edit directly; please reach out on Discord or the TASVideos forums (and not this repo's issue tracker).