C#中是否有类似于'when()'语句的东西或者等价语句?

4

在C#中,是否存在类似于“when”语句的东西?

我需要这个是因为if语句只会在特定时间检查某个属性是否为true,但我希望它能够等待直到该属性变为true

有人知道我可以在C#中做类似于“when”语句的事情吗?


1
最好将您的代码放在那里以便理解您的意图,但如果我理解正确,它应该是 WHILE(true) { } - Hasan Gholamali
5个回答

6
你需要的是SpinWait。例如:SpinWait.SpinUntil(() => condition);它会等待,直到超时(在你指定的超时时间内)或条件得到满足。

4
使用C#已经5年了,但仍然遇到了我从未听说过的事情! - jmdon
2
如果你想浪费电力并让电脑做很多无用的计算,这种方法非常完美。 - TheGeneral
有@TheGeneral,但如果你等待一段时间,你可以在条件中加入一个睡眠。 - gmn
我需要为此使用特定的“using”吗?我找不到它。 - Sebastian
MSDNSpinWait 方法通常不适用于普通应用程序。在大多数情况下,您应该使用 .NET Framework 提供的同步类,例如 Monitor。 - TaW
如果这里有两个线程在操作的话(我不确定有没有),我可能会在该属性的setter中使用自动重置事件或类似的东西。 - gmn

4

虽然没有 when 控制语句,但有两种选项可能满足您的需求:

您可以使用一个 while(predicate){}循环来一直循环,直到满足条件。 predicate 可以是任何返回 true/false 的表达式——只要条件为真,它就会循环。如果您只想等待而不消耗太多 CPU,可以在循环中用 Sleep() 睡眠线程:

while(name == "Sebastian")
{
    // Code to execute
    System.Threading.Thread.Sleep(1000);
}

如果您的属性是数字范围,您可以使用for循环,但这似乎不是您想要的。

我使用了这个方法,但它没有执行 while 循环内的代码。 - Sebastian
你把示例中的 name == "Sebastian" 改成你需要的了吗?记住,只要条件为 true,它就会进入循环,所以你应该设置条件,使得 true 意味着你想再次等待,而当你的条件满足时,它变为 false。如果条件为 true,它肯定会进入循环 - 我刚试过了。 - Peter

2
如果你想处理异步世界,那么你可能需要看一下库Rx.NET。让我们看一个简单的例子:假设你想从控制台读取字符串,并在用户输入单词"hello"时需要在响应中打印"world"。这个简单的例子可以按照以下方式实现:
var inputLines = new Subject<string>();
inputLines.Subscribe(info =>
{
    if (info == "hello")
        Console.Out.WriteLine("world");
});
while (true)
{
    var line = Console.In.ReadLine();
    inputLines.OnNext(line);
}

因此,在 Subscribe(...) 函数中,我们传递了明确的when操作。
在这个简单的Rx.NET示例中,显然不必要并且不应该这样做。但在更复杂的情况下,这是一个非常有用的库。您可以看到,使用反应式扩展,您将应用程序的逻辑与主事件池分离开来,在那里您可以执行与应用程序逻辑无关的其他工作。此外,由于它非常灵活,因此您可以获得此库的高度灵活性-您可以在运行时随时订阅和取消订阅不同的事件。
您可以注意到,在基于事件的范例中解决我的问题的另一种方法。我们可以简单地使用内置事件,如下所示:
public static event EventHandler<string> InputEvent;
public void Run() 
{
    InputEvent += (sender, line) =>  {
        if (line == "hello")
            Console.WriteLine("world");
    };

    while (true) {
        var line = Console.In.ReadLine();
        InputEvent?.Invoke(this, line);
    }
}

这是一个正确的观点,有时候你可以用简单的事件替换响应式扩展,因为它们是相互连接的。但是当你需要从许多事件源构建复杂的管道,并使用许多不同紧密耦合的操作时,响应式扩展允许你以非常声明性的方式构建这个管道。


1
.Net事件的解决方案不错。但是,如果您想传递参数,推荐使用EventHandler作为委托,并从EventArgs派生类派生。 - CodeNotFound

0
你在这里想要实现什么?你是在运行同步进程还是等待异步事件发生?
如果你是同步的,那么使用 while 循环可能是正确的解决方案:
var result = 0;
while(result != 6)
{
    result = RollADie();
    Console.WriteLine($"I rolled a {result}");
}
Console.WriteLine("At last, a six!");

但是 - 如果你正在等待某些异步事件发生,那么需要使用不同的解决方案。异步场景是指你希望你的代码“挂起并等待,什么也不做”,直到条件得到满足。

在这种情况下,现代 C# 解决方案是使用 asyncawait 关键字进行异步编程,以及 Task 类(以及它的泛型版本 Task<TResult>)。这可能有点深入,但这里有一个相当不错的入门教程

重要的是,你不要使用基于 while 的解决方案来处理异步进程。这只会让 CPU 不停地旋转,追逐自己的尾巴,而你真正想要的是“现在停止处理这个,直到 X 发生”。此外,出于相关原因,避免任何基于 while 结合 Thread.Sleep 的解决方案。


0
你可以使用 'async' 和 'await' 来等待某个特定的 'Task' 完成。'await' 有点类似于你需要的 'when' 语句,但它将暂停当前的 'Task' 直到等待的 'Task' 完成并返回任何结果,而不仅仅是当表达式变为 'true' 时。另请参见 TaskCompletionSource

我认为你使用Task来解决问题有些过度了。在这里,我认为简单的while(predicate)就足够了。 - CodeNotFound
1
这在很大程度上取决于操作者的'while'循环是否会导致繁忙等待。我假设'when'意味着等待同一进程的某些其他部分设置某个条件为真,因此涉及任务或线程。 - Kasper van den Berg
1
如果您需要等待某些异步事件,则可以考虑使用库Rx.NET来处理此任务。我们可以创建一些可观察的主题,对应于我们的事件,并订阅一些特定的操作。 - Nikita Sivukhin
1
@NikitaSivukhin 你应该把那个变成一个答案。 - Kasper van den Berg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接