编辑: 这个答案是错误的,但我不能删除它,因为它被标记为正确。请参阅下面@Lockszmith 的答案以获取正确答案。
释义:
在每次 yeald 返回之间永远不会释放锁。注意:但是当枚举器完成时,即当 foreach 循环结束时,它会被释放。
结束编辑
原始答案(错误):
在您的场景中,锁只会被占用一次。所以简而言之,只有一次。但是,您没有处理任何共享资源。当您开始像下面的控制台应用程序那样处理共享资源时,会发生一些有趣的事情。
你会从结果中看到,每次yield都会临时释放锁。另外,请注意,在所有项目都写入控制台之前,不会释放列表 1 上的锁,这表明 GetData() 方法在循环的每次迭代中部分执行,并且必须在每次循环时临时释放锁产量声明。
static void Main(string[] args)
{
object locker = new object();
IEnumerable<string> myList1 = new DataGetter().GetData(locker, "List 1");
IEnumerable<string> myList2 = new DataGetter().GetData(locker, "List 2");
Console.WriteLine("start Getdata");
foreach (var x in myList1)
{
Console.WriteLine("List 1 {0}", x);
foreach(var y in myList2)
{
Console.WriteLine("List 2 {0}", y);
}
}
Console.WriteLine("end GetData");
Console.ReadLine();
}
public class DataGetter
{
private List<string> _data = new List<string>() { "1", "2", "3", "4", "5" };
public IEnumerable<string> GetData(object lockObj, string listName)
{
Console.WriteLine("{0} Starts", listName);
lock (lockObj)
{
Console.WriteLine("{0} Lock Taken", listName);
foreach (string s in _data)
{
yield return s;
}
}
Console.WriteLine("{0} Lock Released", listName);
}
}
}
结果:
start Getdata
List 1 Starts
List 1 Lock Taken
List 1 1
List 2 Starts
List 2 Lock Taken
List 2 1
List 2 2
List 2 3
List 2 4
List 2 5
List 2 Lock Released
List 1 2
List 2 Starts
List 2 Lock Taken
List 2 1
List 2 2
List 2 3
List 2 4
List 2 5
List 2 Lock Released
List 1 3
List 2 Starts
List 2 Lock Taken
List 2 1
List 2 2
List 2 3
List 2 4
List 2 5
List 2 Lock Released
List 1 4
List 2 Starts
List 2 Lock Taken
List 2 1
List 2 2
List 2 3
List 2 4
List 2 5
List 2 Lock Released
List 1 5
List 2 Starts
List 2 Lock Taken
List 2 1
List 2 2
List 2 3
List 2 4
List 2 5
List 2 Lock Released
List 1 Lock Released
end GetData
不过,他这里真正酷的事情是结果。请注意,“开始 GetData”这一行出现在调用 DataGetter().GetData() 之后,但在 GetData() 方法中发生的所有事情之前。这称为延迟执行,它展示了 yield return 语句的美丽和实用性:在外部循环中的任何地方,您都可以跳出循环,并且不会再调用内部循环。这意味着您不必迭代整个内部循环,如果您不需要,这也意味着您将开始更早地获得外部循环的结果。