Just to share that these have already been added::
internal sealed class RefBox<T> where T : class
{
public T Payload;
public RefBox(T value)
{
Payload = value;
}
public T GetPayload()
{
return Payload;
}
}
/// <summary>Closed constructed generic on a reference type (GENERICINST in metadata).</summary>
internal sealed class GenericHolder
{
public RefBox<string> BoxField;
public GenericHolder(string s)
{
BoxField = new RefBox<string>(s);
}
}
/// <summary>Two-arity generic (Pair`2). Exercises declaring token on GENERICINST with two args.</summary>
internal struct Pair<TU, TV>
{
public TU U;
public TV V;
public Pair(TU u, TV v)
{
U = u;
V = v;
}
/// <summary>Instance method on constructed Pair; exercises MethodRef parent = TypeSpec.</summary>
public string Describe()
{
return U.ToString() + "/" + V.ToString();
}
}
/// <summary>Value-type constraint + instance methods on closed generic (MethodRef + FieldRef paths).</summary>
internal sealed class ValCell<T> where T : struct
{
public T Cell;
public void Write(T value)
{
Cell = value;
}
public T Read()
{
return Cell;
}
}
internal static class Program {
private static GenericHolder s_holder;
static void Main() {
var cnt = 0;
var gpioController = GpioController.GetDefault();
var led = gpioController.OpenPin(SC20260.GpioPin.PA8);
led.SetDriveMode(GpioPinDriveMode.Output);
var button = gpioController.OpenPin(SC20260.GpioPin.PB7);
button.SetDriveMode(GpioPinDriveMode.InputPullUp);
s_holder = new GenericHolder("generics-field-ok");
Debug.WriteLine(s_holder.BoxField.GetPayload());
// Local closed generic + array of constructed type
var localBox = new RefBox<string>("generics-local-ok");
Debug.WriteLine(localBox.GetPayload());
var arr = new RefBox<string>[2];
arr[0] = localBox;
arr[1] = s_holder.BoxField;
Debug.WriteLine(arr[0].Payload + " | " + arr[1].Payload);
// Generic method (explicit type args); exercises generic method prefix in signatures
var n = Identity<int>(7);
Debug.WriteLine("Identity<int>: " + n.ToString());
var s = Identity<string>("method-generic-ok");
Debug.WriteLine(s);
// Pair<int,int>: arity-2 GENERICINST; Describe() -> MethodRef on constructed type
var pair = new Pair<int, int>(40, 2);
Debug.WriteLine("Pair<int,int>: " + pair.Describe());
// ValCell<int>: struct type arg + Write/Read -> MethodRef on ValCell`1<int>
var cell = new ValCell<int>();
cell.Write(12345);
Debug.WriteLine("ValCell<int>.Read: " + cell.Read().ToString());
while (true) {
Debug.WriteLine("Hello from TinyCLR7.9! Count: " + cnt++);
Thread.Sleep(250);
led.Write(led.Read() == GpioPinValue.Low ? GpioPinValue.High : GpioPinValue.Low);
if (button.Read() == GpioPinValue.Low)
{
DoTest();
}
}
}
static int counter = 0;
static void DoTest()
{
counter++;
Debug.WriteLine($"Do Test jump to function {counter}");
}
private static T Identity<T>(T value)
{
return value;
}
}
namespace TinyCLRApp10_Task2 {
class Program {
static async Task Main() {
Debug.WriteLine("=== TinyCLR Async/Await Test ===");
// 1. Basic await of a Task that does real work + delay
Debug.WriteLine("[1] Start");
await DoWorkAsync();
Debug.WriteLine("[1] End");
// 2. Task<T> with a return value
Debug.WriteLine("[2] Computing...");
var answer = await ComputeAsync(20, 22);
Debug.WriteLine("[2] 20 + 22 = " + answer.ToString());
// 3. Task.FromResult - already-completed task
var preset = Task.FromResult(100);
var val = await preset;
Debug.WriteLine("[3] FromResult = " + val.ToString());
// 4. Sequential awaits - no parallelism expected, each runs fully
Debug.WriteLine("[4] Sequential 3 x 500 ms...");
var startTicks = DateTime.UtcNow.Ticks;
await Task.Delay(500);
await Task.Delay(500);
await Task.Delay(500);
var elapsedMs = (DateTime.UtcNow.Ticks - startTicks) / TimeSpan.TicksPerMillisecond;
Debug.WriteLine("[4] Elapsed ~" + elapsedMs.ToString() + " ms (expect ~1500)");
// 5. Nested async calls
Debug.WriteLine("[5] Nested...");
await OuterAsync();
Debug.WriteLine("[5] Back in Main");
// 6. Mixed sync work between awaits
Debug.WriteLine("[6] Counting...");
for (var i = 1; i <= 3; i++) {
await Task.Delay(300);
Debug.WriteLine("[6] tick " + i.ToString());
}
Debug.WriteLine("=== All tests passed ===");
var cnt = 0;
while (true) {
Debug.WriteLine("alive " + (cnt++).ToString());
Thread.Sleep(1000);
}
}
static async Task DoWorkAsync() {
Debug.WriteLine(" Working...");
await Task.Delay(2000);
Debug.WriteLine(" Done");
}
static async Task<int> ComputeAsync(int a, int b) {
await Task.Delay(200);
return a + b;
}
static async Task OuterAsync() {
Debug.WriteLine(" Outer begin");
await InnerAsync();
Debug.WriteLine(" Outer end");
}
static async Task InnerAsync() {
Debug.WriteLine(" Inner begin");
await Task.Delay(300);
Debug.WriteLine(" Inner end");
}
}
}
namespace TinyCLRApp10_List {
class Program {
static void Main()
{
var list = new System.Collections.Generic.List<int>();
list.Add(1);
list.Add(2);
list.Add(3);
Debug.WriteLine(list.Count.ToString()); // 3
foreach (var item in list)
Debug.WriteLine(item.ToString()); // 1, 2, 3
list.Remove(2);
Debug.WriteLine(list.Count.ToString()); // 2
var cnt = 0;
while (true) {
Debug.WriteLine("Hello from TinyCLR! Count: " + cnt++);
Thread.Sleep(1000);
}
}
}
}
namespace TinyCLRApp10_Tuble {
class Program {
static void Main() {
Console.WriteLine("=== Tuple test ===");
// 1. Basic 2-tuple via factory
var pair = Tuple.Create(42, "hello");
Debug.WriteLine("[1] Item1 = " + pair.Item1.ToString());
Debug.WriteLine("[1] Item2 = " + pair.Item2);
Debug.WriteLine("[1] ToString = " + pair.ToString()); // (42, hello)
// 2. 3-tuple of ints
var coords = Tuple.Create(10, 20, 30);
Debug.WriteLine("[2] coords = " + coords.ToString()); // (10, 20, 30)
Debug.WriteLine("[2] sum = " + (coords.Item1 + coords.Item2 + coords.Item3).ToString());
// 3. Value-based equality
var a = Tuple.Create(1, 2);
var b = Tuple.Create(1, 2);
var c = Tuple.Create(1, 3);
Debug.WriteLine("[3] a.Equals(b) = " + a.Equals(b).ToString()); // True
Debug.WriteLine("[3] a.Equals(c) = " + a.Equals(c).ToString()); // False
Debug.WriteLine("[3] ReferenceEquals(a,b) = " + object.ReferenceEquals(a, b).ToString()); // False
// 4. Hash codes: equal tuples -> same hash
Debug.WriteLine("[4] a.GetHashCode == b.GetHashCode : "
+ (a.GetHashCode() == b.GetHashCode()).ToString()); // True
// 5. Tuple as a return value (the classic use case)
var result = Divide(17, 5);
Debug.WriteLine("[5] 17 / 5 = " + result.Item1.ToString() + " remainder " + result.Item2.ToString());
// 6. Nullable / mixed types (5-arity)
var t5 = new Tuple<int, string, bool, int, string>(1, "two", true, 4, "five");
Debug.WriteLine("[6] t5 = " + t5.ToString());
Debug.WriteLine("[6] t5.Item3 = " + t5.Item3.ToString());
// 7. Tuple with null element
var withNull = Tuple.Create<string, string>("A", null);
Debug.WriteLine("[7] withNull = " + withNull.ToString()); // (A, )
Debug.WriteLine("=== Done ===");
var cnt = 0;
while (true) {
Debug.WriteLine("alive " + (cnt++).ToString());
Thread.Sleep(1000);
}
}
// Classic pattern: return two values without an out parameter
static Tuple<int, int> Divide(int a, int b) => Tuple.Create(a / b, a % b);
}
}
This is not a promise yet, as it depends on last-minute approval, but it has already been added and is running on TinyCLR.