Hello everyone! Today I want to share a particularly interesting topic – the implementation of coroutines in C#. As a developer who often deals with asynchronous programming, I understand the importance of coroutines in enhancing program performance and simplifying code structure. Let’s explore how to implement a simple yet powerful coroutine library in C#!
What Are Coroutines?
Coroutines can be understood as a type of “pausable function”. Imagine when you are reading a novel and need to answer a phone call, you place a bookmark on the current page and continue reading after the call – this is the basic principle of coroutines! In programming, coroutines allow us to save the current state during execution and continue from that saved point later.
public interface ICoroutine
{
bool MoveNext();
void Reset();
object Current { get; }
}
Implementing Coroutine State Machine
In C#, we can implement coroutines using the state machine pattern. Each state represents a certain point of execution in the program.
public class SimpleCoroutine : ICoroutine
{
private int _state = 0;
private object _current;
public object Current => _current;
public bool MoveNext()
{
switch (_state)
{
case 0:
// First execution point
_current = "Step 1";
_state = 1;
return true;
case 1:
// Second execution point
_current = "Step 2";
_state = 2;
return true;
case 2:
// Coroutine ends
return false;
default:
return false;
}
}
public void Reset()
{
_state = 0;
_current = null;
}
}
Using Yield for Elegant Coroutines
C# provides us with a more elegant way to implement coroutines using the <span>yield</span>
keyword. It automatically generates state machine code for us.
public class YieldCoroutine
{
public IEnumerator<string> RunTask()
{
Console.WriteLine("Starting task");
yield return "Step 1 completed";
// Simulate time-consuming operation
Thread.Sleep(1000);
yield return "Step 2 completed";
Console.WriteLine("Task ended");
}
}
</string>
Coroutine Manager
To better manage coroutines, we need a coroutine manager:
public class CoroutineManager
{
private List<ienumerator> _coroutines = new List<ienumerator>();
public void StartCoroutine(IEnumerator coroutine)
{
_coroutines.Add(coroutine);
}
public void UpdateCoroutines()
{
for (int i = _coroutines.Count - 1; i >= 0; i--)
{
if (!_coroutines[i].MoveNext())
{
_coroutines.RemoveAt(i);
}
}
}
}
</ienumerator></ienumerator>
Practical Application Example
Let’s look at a practical application example in a game:
public class GameController
{
private CoroutineManager _coroutineManager = new CoroutineManager();
public IEnumerator PlayerAttackSequence()
{
Console.WriteLine("Player starts attacking");
yield return new WaitForSeconds(1.0f); // Wait for 1 second
Console.WriteLine("Playing attack animation");
yield return new WaitForSeconds(0.5f);
Console.WriteLine("Dealing damage");
yield return new WaitForSeconds(0.3f);
Console.WriteLine("Attack ended");
}
public void StartAttack()
{
_coroutineManager.StartCoroutine(PlayerAttackSequence());
}
}
Tips:
-
Coroutines are not threads! They execute on the same thread but can elegantly handle asynchronous logic.
-
When using coroutines, pay attention to memory management to ensure there are no coroutine leaks.
-
In Unity game development, coroutines are particularly useful for implementing animations, delayed execution, and more.
Notes:
-
Runtime environment: .NET 6.0 and above
-
Namespaces: You need to include
<span>System.Collections</span>
and<span>System.Collections.Generic</span>
-
Performance considerations: The state machine implementation of coroutines incurs some performance overhead, but it is much smaller than the overhead of thread switching.
Unit Test Example
[TestClass]
public class CoroutineTests
{
[TestMethod]
public void TestSimpleCoroutine()
{
var coroutine = new SimpleCoroutine();
Assert.IsTrue(coroutine.MoveNext());
Assert.AreEqual("Step 1", coroutine.Current);
Assert.IsTrue(coroutine.MoveNext());
Assert.AreEqual("Step 2", coroutine.Current);
Assert.IsFalse(coroutine.MoveNext());
}
}
Friends, that’s all for today’s C# learning journey! Remember to write code, and feel free to ask questions in the comments. I wish everyone a pleasant learning experience and may your C# development journey go further! Code changes the world, and see you next time!