fourni votre plate-forme a une implémentation de System.Collections.Concurrent.BlockingCollection
, voici facile si façon pas tout à fait efficace de le faire:
class ConsoleReader {
private readonly BlockingCollection<int> buffer = new BlockingCollection<int>(1);
private readonly Thread readThread;
public ConsoleReader() {
readThread = new Thread(() => {
if (Console.IsInputRedirected) {
int i;
do {
i = Console.Read();
buffer.Add(i);
} while (i != -1);
} else {
while (true) {
var consoleKeyInfo = Console.ReadKey(true);
if (consoleKeyInfo.KeyChar == 0) continue; // ignore dead keys
buffer.Add(consoleKeyInfo.KeyChar);
}
}
});
}
public void Start() {
readThread.Start();
}
public int? Next {
get {
int result;
return buffer.TryTake(out result, 0) ? result : default(int?);
}
}
}
Avertissement: cette réponse n'a pas été réellement testé sur Mono, et brièvement sur la pleine Plate-forme .NET. Vous pouvez pimenter ceci avec un Task
au lieu d'un Thread
, une annulation correcte etc., mais cela ne changera pas l'inefficacité centrale d'attendre explicitement sur une opération synchrone (qui Console.Read
et Console.ReadKey
sont tous les deux). Les E/S de console asynchrones portables ne sont pas proposées par .NET lui-même. L'implémenter vous-même sur toutes les plateformes (en utilisant les fonctionnalités du système d'exploitation) est possible, mais décidément non trivial.
Il n'y a pas de manière indépendante de la plate-forme de faire async stdin I/O, ce qui explique pourquoi la BCL n'essaie pas. Les opérations de lecture sur le flux d'entrée standard s'exécutent de manière synchrone, c'est-à-dire qu'elles se bloquent jusqu'à ce que l'opération de lecture spécifiée soit terminée. " Peut-il être mis en œuvre sur Mono? Probablement, si vous aimez P/Invoke et '# if 'pour prendre soin des différentes plates-formes. Il ne vaut certainement pas la peine de le faire, par opposition à la rotation d'un thread pour envelopper l'opération de synchronisation (et en utilisant 'Console.IsInputRedirected' pour distinguer ce cas). –
@JeroenMostert écrire plus de code est exactement ce que j'essaie d'éviter. Je vais donner un exemple vraiment succint de la façon dont cela peut être fait le plus rapidement possible. L'idée est d'éviter de dépenser une quantité non négligeable de code ou d'effort sur le problème. Allons, c'est 2017! Et nous ne pouvons pas lire un octet d'un flux sans threads ou blocage! – alamar
Il s'agit en effet de 2017, mais les E/S de console non bloquantes et non bloquantes ne sont tout simplement pas une fonctionnalité très demandée. La mode a toujours été des applications console qui traitent sereinement leur entrée d'une manière synchrone, monothread. Si vous êtes satisfait de l'interrogation plutôt que de la vraie async (comme vous l'êtes), il est assez facile à faire sur Unix et Win32 (bien que non, bien sûr, de la même manière, ce serait trop facile), mais .NET le plus petit dénominateur commun, ce qui n'aide pas. Je ne pouvais pas trouver une solution triviale dans 10 minutes. Ne pas dire qu'il n'y en a pas *. –