Checked и unchecked 14 страница.
Методы Sum можно, например, использовать для вычисления сумм из списка строк с деталями заказов. class Detail void ComputeSums() { В первом вызове orderDetails.Sum оба метода Sum применимы, поскольку анонимная функция d => d.UnitCount совместима и с Func<Detail,int> и с Func<Detail,double>. Однако при разрешении перегрузки будет выбран первый метод Sum, потому что преобразование в Func<Detail,int> оказывается лучше преобразования в Func<Detail,double>. Во втором вызове orderDetails.Sum применим только второй метод Sum, потому что анонимная функция d => d.UnitPrice * d.UnitCount возвращает значение типа double. Поэтому в данном вызове при разрешении перегрузки будет выбран второй метод Sum. 7.15.4 Анонимные функции и динамическая привязка Анонимная функция не может быть получателем, аргументом или операндом динамически привязанной операции. 7.15.5 Внешние переменные; Любая локальная переменная, параметр значения или массив параметров, область действия которого включает лямбда_выражение или выражение_анонимного_метода, называется внешней переменной анонимной функции. В функции-члене экземпляра для класса значение this считается параметром значения и является внешней переменно любой анонимной функции, содержащейся в функции-члене. 7.15.5.1 Захваченные внешние переменные Когда анонимная функция ссылается на внешнюю переменную, внешнюю переменную называют захваченной анонимной функцией. Обычно срок жизни локальной переменной ограничен выполнением блока или оператора, с которым она связана (§5.1.7). Однако срок жизни захваченной внешней переменной увеличивается по крайней мере до того, как делегат или дерево выражения, созданное из анонимной функции, становится объектом для процесса сборки мусора. В примере using System; delegate int D(); class Test static void Main() { локальная переменная x захватывается анонимной функцией и ее срок жизни увеличивается по крайней до тех пор, пока делегат, возвращенный из F, не станет объектом для процесса сборки мусора (что произойдет только в самом конце программы). Поскольку каждый вызов анонимной функции работает с одним экземпляром x, пример имеет следующий вывод: 1 Когда локальная переменная или параметр значения захватывается анонимной функцией, локальная переменная или параметр больше не считается фиксированной переменной (§18.3), а вместо этого считается перемещаемой переменной. Поэтому в любом небезопасном коде, который получает адрес захваченной внешней переменной, сначала необходимо использовать оператор fixed, чтобы зафиксировать переменную. Заметьте, в отличие от незахваченной переменной, захваченная локальная переменная может быть одновременно использоваться в нескольких потоках выполнения. 7.15.5.2 Создание экземпляров локальных переменных Считается, что для локальной переменной создается экземпляр, когда выполнение входит в область действия переменной. Например, при вызове следующего метода экземпляр локальной переменной x создается и инициализируется три раза, один раз для каждой итерации цикла. static void F() { Однако если перенести объявления x за пределы цикла, то экземпляр x будет создаваться только один раз. static void F() { Если локальная переменная не захвачена, то не существует способа точно отследить, сколько раз создавались ее экземпляры, потому что сроки жизни экземпляров не связаны. Для каждого экземпляра можно просто использовать одно место хранения. Однако когда локальная переменная захватывается анонимной функцией, результат создания экземпляра становится очевидным. В примере using System; delegate void D(); class Test static void Main() { дает на выходе: 1 Однако при переносе объявления x за пределы цикла: static D[] F() { вывод имеет вид: 5 Если в цикле for объявляется переменная итерации, то сама эта переменная считается объявленной за пределами цикла. Таким образом, если изменить пример, чтобы захватывать саму переменную итерации static D[] F() { то будет захвачен только один экземпляр переменной итерации. В этом случае вывод имеет вид 3 Делегаты анонимных функций могут иметь некоторые общие захваченные переменные и в то же время иметь отдельные экземпляры других переменных. Например, если F изменить на static D[] F() { то три делегата будут захватывать один экземпляр x, но разные экземпляры y. Вывод будет иметь вид: 1 1 Отдельные анонимные функции могут захватывать один экземпляр внешней переменной. В следующем примере: using System; delegate void Setter(int value); delegate int Getter(); class Test две анонимные функции захватывают один экземпляр локальной переменной x и поэтому они могут «взаимодействовать» через эту переменную. Вывод в данном примере имеет вид: 5 7.15.6 Вычисление выражений анонимных функций Анонимная функция F всегда должна преобразовываться в тип делегата D или тип дерева выражения E либо напрямую, либо с помощью выполнения выражения создания делегата new D(F). Это преобразование определяет результат анонимной функции, как описано в разделе §6.5. 7.16 Выражения запросов; Выражения запросов представляют собой подмножество синтаксических конструкций языка для запросов, похожих запросы иерархических или реляционных языков запросов, таких как SQL и XQuery.
|