Ответ 1
Изменить: Этот ответ был неправильным, но я не могу удалить его, поскольку он был помечен как правильный. Пожалуйста, см. @Lockszmith ответ ниже для правильного ответа.
перефразировать:
Блокировка НИКОГДА не освобождается между каждым возвратом yeald. ПРИМЕЧАНИЕ. Однако он освобождается, когда перечислитель выполнен, то есть когда цикл foreach завершается.
Редактировать конец
Оригинальный ответ (неверный):
В вашем сценарии блокировка будет выполняться только один раз. Короче говоря, только один раз. Однако вы не имеете никаких общих ресурсов. Когда вы начинаете работать с общими ресурсами, например, в консольном приложении ниже, происходят некоторые интересные вещи.
Вы увидите по результатам, что блокировка временно освобождается при каждом выходе. Также обратите внимание, что блокировка в списке 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
Однако, он действительно здорово, вот результаты. Обратите внимание, что строка "start GetData" возникает после вызова метода DataGetter(). GetData(), но перед тем, что происходит в методе GetData(). Это называется отложенным исполнением, и оно демонстрирует красоту и полезность оператора return yield: в любом месте внутри вашего внешнего цикла вы можете выйти из цикла, и больше не будет вызовов во внутренний цикл. Это означает, что вам не нужно перебирать весь внутренний цикл, если вам это не нужно, и это также означает, что вы начнете получать результаты в свой внешний цикл раньше.