Skip to content
This repository was archived by the owner on Oct 28, 2025. It is now read-only.

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 

Repository files navigation

CHATGPT: 看起來你是在問:能不能用 IAsyncEnumerableawait foreach)+ switch 來做一個「訊息迴圈」(message loop),讓風格接近 WinNT/Win32 的 GetMessage/TranslateMessage/DispatchMessage?答案是可以,而且在 .NET 裡可用 System.Threading.Channels 或任何能提供 IAsyncEnumerable<T> 的來源,寫出很像「訊息泵浦」的模式。(Microsoft Learn)

下面是一個最小範例:用 Channel<AppMessage> 當佇列,生產者把各種訊息丟進去;消費者用 await foreachReadAllAsync 拉訊息,並用 switch(含型別/屬性樣式比對)分派處理,整體結構就像 Win32 的 while(GetMessage(&msg)) { TranslateMessage(&msg); DispatchMessage(&msg); }

using System;
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
using System.Collections.Generic;

interface AppMessage { }               // 基底訊息型別
record Click(int X, int Y) : AppMessage;
record Key(char Ch)       : AppMessage;
record Tick(DateTime At)  : AppMessage;
record Quit()             : AppMessage; // 類似 WM_QUIT

static class MessageBus
{
    public static Channel<AppMessage> Create() =>
        Channel.CreateUnbounded<AppMessage>(new UnboundedChannelOptions
        {
            SingleReader = false, SingleWriter = false
        });
}

class Program
{
    static async IAsyncEnumerable<AppMessage> Pump(ChannelReader<AppMessage> reader,
                                                   [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken ct = default)
    {
        await foreach (var msg in reader.ReadAllAsync(ct))
            yield return msg; // 這裡就像 GetMessage 取出佇列中的訊息
    }

    static async Task Main()
    {
        var ch = MessageBus.Create();
        var cts = new CancellationTokenSource();

        // 生產者(模擬事件產生)
        // or stream source
        _ = Task.Run(async () =>
        {
            await ch.Writer.WriteAsync(new Click(100, 200));
            await ch.Writer.WriteAsync(new Key('A'));
            await ch.Writer.WriteAsync(new Tick(DateTime.UtcNow));
            await Task.Delay(50);
            await ch.Writer.WriteAsync(new Quit());     // 類似 PostQuitMessage
            ch.Writer.Complete();
        });

        // 消費者(訊息迴圈)
        await foreach (var msg in Pump(ch.Reader, cts.Token))
        {
            switch (msg)
            {
                case Click(var x, var y):
                    Console.WriteLine($"Click at ({x},{y})");
                    break;

                case Key(var ch):
                    Console.WriteLine($"Key: {ch}");
                    break;

                case Tick(var at):
                    Console.WriteLine($"Tick @ {at:o}");
                    break;

                case Quit:
                    Console.WriteLine("Quit received. Exiting loop.");
                    goto ExitLoop; // 或設旗標跳出

                default:
                    // 類似 DispatchMessage 找不到處理者
                    Console.WriteLine($"Unhandled: {msg.GetType().Name}");
                    break;
            }
        }
    ExitLoop:;
    }
}

為什麼這個模式「像」 WinNT/Win32 的訊息泵浦

  • 來源佇列:Win32 以執行緒訊息佇列為來源;上面用 Channel<T> 提供非同步的生產者/消費者佇列(多讀/多寫、內建同步)。(Microsoft Learn)
  • 拉取模型:Win32 用 GetMessage 取出下一則訊息;上面用 await foreach 消費 IAsyncEnumerable<T>(來自 ChannelReader.ReadAllAsync),語意是「逐則非同步取得」。(Microsoft Learn)
  • 分派:Win32 的 DispatchMessage 呼叫對應視窗程序;上面用 switch + 模式比對把不同訊息分派到對應的處理程式。(Microsoft Learn)
  • 結束條件:Win32 的 WM_QUITGetMessage 返回 0 以中止迴圈;上面用 Quit 訊息或關閉 channel 來跳出。(Microsoft Learn)

延伸建議

  • 若你要高吞吐、背壓控制,可用 BoundedChannelOptions 設定容量與丟棄策略。(Microsoft Learn)
  • 想做多工分派,可在 switch 中啟動對應 Task,或改為多個消費者共同讀同一個 ChannelReaderChannel<T> 支援多讀多寫)。(Microsoft Learn)
  • 若來源不是 Channel,任何能提供 IAsyncEnumerable<T> 的 API 都能套用同樣的 await foreach + switch 模式。(Microsoft Learn)

參考來源

  • Win32 訊息迴圈(GetMessage/DispatchMessage/TranslateMessage)概述與範例,Microsoft Learn。(Microsoft Learn)
  • DispatchMessage 說明,Microsoft Learn。(Microsoft Learn)
  • C# 非同步列舉(IAsyncEnumerableawait foreach)介紹(MSDN Magazine 存檔)。(Microsoft Learn)
  • System.Threading.Channels 介紹與 API 參考,Microsoft Learn。(Microsoft Learn)
  • C# 模式比對與 switch/switch expression 語法說明,Microsoft Learn。(Microsoft Learn)
  • 進階補充:Win32 訊息迴圈解析(winprog.org 教學)。(Winprog)

如果你有具體的訊息型別或要串接的 I/O 來源(例如 Socket、GUI 事件、訊息匯流排),我可以直接幫你把上面骨架改成你的實作。

About

No description or website provided.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages