-
-
Save shoaibshakeel381/eb708b1decf439c9dce8019717d75a18 to your computer and use it in GitHub Desktop.
This is the code I demonstrated at the .NET Community Standup on 2023/1/12 with comments to explain how it works.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Reflection.Emit; | |
using System.Runtime.CompilerServices; | |
using System.Threading.Tasks; | |
#nullable disable | |
// The stand up link https://www.youtube.com/watch?v=jaPk6Nt33KM | |
// String vs. string | |
// - string is a C# keyword that binds to System.String in corelib | |
// - String is just another name. Most of the time it binds to the same type | |
// as string but it doesn't have to. Defining the type String here lets us | |
// subvert expectations around String behavior | |
// | |
// More details | |
// https://blog.paranoidcoding.com/2019/04/08/string-vs-String-is-not-about-style.html | |
class String { | |
public static implicit operator String(dynamic var) => null; | |
} | |
// Let's define a few type names that mirror contextual keywords. This lets | |
// us subvert expectations by having the compiler bind these as types | |
// instead of keywords. | |
class record { } | |
class where { } | |
class dynamic { } | |
class var { | |
// This defines a property named dynamic that has type dynamic (defined | |
// above). It's no different than Color Color (common in UI) because in | |
// this program dynamic is a type. The only difference is expectation | |
// around what dynamic should be. | |
dynamic dynamic => null; | |
// Even though we defined a type named record, this is not a method. Instead | |
// this is a record definition. That is because record is one of the few | |
// places where C# took a back compat hit on upgrade and always treats | |
// record as a keyword. | |
record nameof(where String = null) | |
{ | |
} | |
// The @ in front of record causes the language to not treat record as a | |
// keyword but as a normal identifier. That makes this a normal method | |
// where named orderby (a contextual keyword but for back compat reasons | |
// have to accept it as a member name). | |
// | |
// The @ trick goes all the way back to C# 1.0 and can be applied to _any_ | |
// keyword. That is what allows us to declare a parameter named @int below | |
// where the type is string (not String) | |
@record orderby(string @int = null) | |
{ | |
// Here String binds to our type and that has an implicit conversion from | |
// the type dynamic. | |
String s = this.dynamic; | |
// Didn't want to return so throw instead. ;) | |
throw null; | |
} | |
async Task<int> M() { | |
// This is a local of type var (see above) named var that initialized | |
// via a target typed new expression. | |
var var = new(); | |
// Here we call var.async and await the result. | |
await var.async(new async()); | |
return 0; | |
} | |
// The buffalo example. | |
// | |
// - This is a method named async | |
// - The method is async, can contain await expressions | |
// - The return type is class async | |
// - The first parameter is of type class async and has a name async | |
async async async(async async) => | |
// This is await on a type which satisfies the task-like pattern | |
// hence can be awaited | |
await async; | |
} | |
// Do you C what I'm doing here? | |
// Can't resist a good dad joke | |
class C{ } | |
// This is a typed named await that implements the awaiter pattern | |
// in C#. | |
class await : INotifyCompletion { | |
public bool IsCompleted => true; | |
public void GetResult() { } | |
public void OnCompleted(Action continuation) { } | |
} | |
// This is a type async which satisfies the Task-like pattern and thus | |
// can be the return type on an async method. | |
[AsyncMethodBuilder(typeof(builder))] | |
class async { | |
public await GetAwaiter() => throw null; | |
} | |
class builder | |
{ | |
public builder() { } | |
public static builder Create() => new(); | |
public void SetResult() { } | |
public void SetException(Exception e) { } | |
public void Start<TStateMachine>(ref TStateMachine stateMachine) | |
where TStateMachine : IAsyncStateMachine => throw null; | |
public async Task => null; | |
public void AwaitOnCompleted<TAwaiter, TStateMachine>( | |
ref TAwaiter awaiter, ref TStateMachine stateMachine) | |
where TAwaiter : INotifyCompletion | |
where TStateMachine : IAsyncStateMachine => throw null; | |
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>( | |
ref TAwaiter awaiter, ref TStateMachine stateMachine) | |
where TAwaiter : ICriticalNotifyCompletion | |
where TStateMachine : IAsyncStateMachine => throw null; | |
public void SetStateMachine(IAsyncStateMachine stateMachine) => throw null; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment