在Unity3D中,有一些协程可以在其中调用WaitUntil()
,直到语句变为true,例如当字符串不为空时。
string str="";
yield return new WaitUntil(()=>str!="");
我发现它非常有用,并希望在VS中使用它。
我创建了两个类,比如A和B,
class A
{
public B b;
public void Set(B bb)
{
b = bb;
b.Str = "Test";
b.ARE.Set();
}
}
class B
{
public string Str="";
public AutoResetEvent ARE = new AutoResetEvent(false);
public B()
{
Thread t = new Thread(Run);
t.Start();
}
private void Run()
{
ARE.WaitOne();
MessageBox.Show(String.Format($"The new string is {Str}");
}
}
public static void Main()
{
A a = new A();
B b = new B();
a.Set(b);
}
正如您所看到的,B的执行依赖于A设置B的AutoResetEvent
。
有没有办法让B自己处理?
我对Task.WhenAll
和其他主题做了一些研究,但我真的不知道如何使用它,最后,我认为AutoResetEvent
更适合这份工作。当然,我可能错了!
PS。我尽量避免像while(Str=="");
这样的东西,因为它处理量很大!
即使它在不同的线程上运行,它仍然会占用不必要的内存和处理能力。
因此,如果可能的话,我想完全推迟,直到满足继续的条件。
非常感谢你的帮助!
非常感谢!
我不是Unity专家,但据我所知,Unity在游戏的每一帧都调用Update()
函数。同样基于文档,它看起来像这样(Unity(:
yield return WaitUntil(() => condition);
与此相同(纯C#(:
while (!condition)
yield return null;
在没有详细说明强大的yield
关键字的情况下,这两个关键字都返回一个IEnumerator
。每次你";移动到下一个";迭代器的值,则执行函数并返回下一个值。只要有要返回的值,包括null
,MoveNext()
就会返回true
。
基本上,WaitUntil()
似乎是某种Unity方言,表示纯C#中的等价物。我怀疑像StartCoroutine()
这样的东西是类似的启动线程的机制(不确定这个(。
以下是一个工作程序,试图解释发生了什么:
using System;
using System.Collections;
using System.Threading;
namespace ConsoleTest
{
public class Program
{
private static int frameCounter;
public class B
{
public string MyString { get; set; }
public IEnumerator Run()
{
while (string.IsNullOrEmpty(MyString))
{
Console.WriteLine("Nothing here yet..."); // This is printed every time MoveNext() is called on the iterator.
yield return null;
}
// MyString is not null anymore: print this.
// This is also the end of the enumerator: no more values will be returned.
Console.WriteLine("MyString has been set after we " + MyString);
}
}
public static void Main()
{
// This simulates Unity's engine by generating one frame every 500ms.
var frameTimer = new Timer(_ => UpdateFrameCounter(), null, 0, 500);
// Creates an instance of B and get the enumerator by calling Run():
var b = new B();
var enumerator = b.Run();
// As long as there are values being returned (by yield), stay in this loop.
// Here, this means basically "as long as b.MyString is null or empty".
while (enumerator.MoveNext())
{
// Demo purposes: block main thread for 1sec.
Thread.Sleep(1000);
// At frame 10, set the value of b.MyString
if (frameCounter == 10)
{
b.MyString = "reached 10 frames.";
}
}
// We'll reach this when there are no more values to be returned, i.e. enumerator.MoveNext() == false.
// Stop the timer and quit.
frameTimer.Change(Timeout.Infinite, Timeout.Infinite);
Console.WriteLine("Press any key to quit...");
Console.ReadKey();
}
public static void UpdateFrameCounter()
{
// Update frame counter (-> Unity engine).
Console.WriteLine($"Frame counter: {++frameCounter}");
}
}
}
EDIT
要准确使用您的示例,您可以将b.Str
设置为属性,然后重置其中的事件:
// In class B:
private string str = string.Empty; // private field
public string Str // public property
{
get => str;
set
{
str = value;
ARE.Set(); // this is called each time b.Str value is set
}
}
这样,当A或任何其他类设置b.Str的值时,ARE
将自动设置,而A不必担心或知道。