Студопедия Главная Случайная страница Обратная связь

Разделы: Автомобили Астрономия Биология География Дом и сад Другие языки Другое Информатика История Культура Литература Логика Математика Медицина Металлургия Механика Образование Охрана труда Педагогика Политика Право Психология Религия Риторика Социология Спорт Строительство Технология Туризм Физика Философия Финансы Химия Черчение Экология Экономика Электроника

Try-catch-finally 13 страница





Список вызова делегата, созданного на базе анонимной функции, содержит одну запись. Конечные объект и метод делегата не определены. В частности, не определено, является ли конечный объект делегата объектом null, а также значение this включающей функции-члена или любого другого объекта.

Допускаются (но не являются обязательными) преобразования семантически идентичных анонимных функций с одинаковым (возможно пустым) набором экземпляров внешних переменных к одному типу делегата. В результате таких преобразований возвращается один экземпляр делегата. Термин «семантически идентичные» означает, что выполнение анонимных функций с одинаковыми аргументами во всех случаях дает одинаковые результаты. Это правило позволяет оптимизировать код, аналогичный приведенному ниже.

delegate double Function(double x);

class Test
{
static double[] Apply(double[] a, Function f) {
double[] result = new double[a.Length];
for (int i = 0; i < a.Length; i++) result[i] = f(a[i]);
return result;
}

static void F(double[] a, double[] b) {
a = Apply(a, (double x) => Math.Sin(x));
b = Apply(b, (double y) => Math.Sin(y));
...
}
}

Поскольку делегаты двух анонимных функций имеют одинаковые (возможно пустые) наборы внешних записанных переменных, а сами функции являются семантически идентичными, при компиляции делегаты могут ссылаться на один конечный метод. Соответственно, компилятор может возвращать одинаковые экземпляры делегата по результатам выполнения выражений обеих анонимных функций.

6.5.2 Вычисление преобразования анонимной функции к типу дерева выражений

В результате преобразования анонимной функции к типу дерева выражений создается дерево выражений (§4.6). Точнее говоря, в результате вычисления преобразования анонимной функции создается объектная структура, представляющая саму функцию. Точная структура дерева выражений, а также процесс его построения указываются при реализации.

6.5.3 Пример реализации;

В данном разделе описывается возможная реализация преобразования анонимных функций в терминах других конструкций C#. Приведенная реализация базируется на принципах, используемых компилятором Microsoft C#, и не является ни обязательной, ни единственно возможной. Здесь приводится лишь краткое описание преобразований к дереву выражений, поскольку полная семантика таких преобразований в данной спецификации не рассматривается.

Далее в разделе рассматривается несколько примеров кода, содержащих анонимные функции с различными характеристиками. Для каждого примера представлен соответствующий код, в котором используются только другие конструкции C#. В данных примерах идентификатор D представляет следующий тип делегата:

public delegate void D();

Анонимная функция простейшего вида не записывает внешние переменные:

class Test
{
static void F() {
D d = () => { Console.WriteLine("test"); };
}
}

Это можно преобразовать в код создания экземпляра делегата, ссылающегося на создаваемый компилятором статический метод, в который помещается код анонимной функции:

class Test
{
static void F() {
D d = new D(__Method1);
}

static void __Method1() {
Console.WriteLine("test");
}
}

В следующем примере анонимная функция ссылается на члены экземпляра this:

class Test
{
int x;

void F() {
D d = () => { Console.WriteLine(x); };
}
}

Это можно преобразовать в создаваемый компилятором метод экземпляра, содержащий код анонимной функции:

class Test
{
int x;

void F() {
D d = new D(__Method1);
}

void __Method1() {
Console.WriteLine(x);
}
}

В этом примере анонимная функция записывает локальную переменную:

class Test
{
void F() {
int y = 123;
D d = () => { Console.WriteLine(y); };
}
}

Время существования локальной переменной необходимо увеличить как минимум до времени существования делегата анонимной функции. Для этого можно поместить (поднять) локальную переменную в поле создаваемого компилятором класса. В этом случае создание экземпляра локальной переменной (§7.15.5.2) будет соответствовать созданию экземпляра класса компилятором. Обращение к локальной переменной будет соответствовать обращению к полю экземпляра создаваемого компилятором класса. Кроме того, анонимная функция становится методом экземпляра создаваемого компилятором класса:

class Test
{
void F() {
__Locals1 __locals1 = new __Locals1();
__locals1.y = 123;
D d = new D(__locals1.__Method1);
}

class __Locals1
{
public int y;

public void __Method1() {
Console.WriteLine(y);
}
}
}

Следующая анонимная функция записывает this, а также две локальные переменные с различным временем существования:

class Test
{
int x;

void F() {
int y = 123;
for (int i = 0; i < 10; i++) {
int z = i * 2;
D d = () => { Console.WriteLine(x + y + z); };
}
}
}

Здесь компилятором создается класс для каждого блока оператора, в котором выполняется запись локальных переменных. За счет этого локальные переменные в каждом блоке имеют различное время существования. Экземпляр класса __Locals2, создаваемого компилятором для внутреннего блока оператора, включает в себя локальную переменную z и поле, содержащее ссылку на экземпляр __Locals1. Экземпляр класса __Locals1, создаваемого компилятором для внешнего блока оператора, включает в себя локальную переменную y и поле, содержащее ссылку на объект this включающей функции-члена. При такой структуре данных с помощью экземпляра __Local2 возможно обращение ко всем записанным внешним переменным. Таким образом, код анонимной функции реализуется как метод экземпляра этого класса.

class Test
{
void F() {
__Locals1 __locals1 = new __Locals1();
__locals1.__this = this;
__locals1.y = 123;
for (int i = 0; i < 10; i++) {
__Locals2 __locals2 = new __Locals2();
__locals2.__locals1 = __locals1;
__locals2.z = i * 2;
D d = new D(__locals2.__Method1);
}
}

class __Locals1
{
public Test __this;
public int y;
}

class __Locals2
{
public __Locals1 __locals1;
public int z;

public void __Method1() {
Console.WriteLine(__locals1.__this.x + __locals1.y + z);
}
}
}

Способ, аналогичный применяемому здесь для записи локальных переменных, может использоваться при преобразовании анонимных функций к деревьям выражений. Ссылки на создаваемые компилятором объекты могут храниться в дереве выражений, а обращение к локальным переменным может быть представлено как обращение к полям этих объектов. Преимущество такого подхода заключается в том, что локальные переменные с нулификацией (поднятые) могут совместно использоваться делегатами и деревьями выражений.







Дата добавления: 2015-09-07; просмотров: 585. Нарушение авторских прав; Мы поможем в написании вашей работы!




Практические расчеты на срез и смятие При изучении темы обратите внимание на основные расчетные предпосылки и условности расчета...


Функция спроса населения на данный товар Функция спроса населения на данный товар: Qd=7-Р. Функция предложения: Qs= -5+2Р,где...


Аальтернативная стоимость. Кривая производственных возможностей В экономике Буридании есть 100 ед. труда с производительностью 4 м ткани или 2 кг мяса...


Вычисление основной дактилоскопической формулы Вычислением основной дактоформулы обычно занимается следователь. Для этого все десять пальцев разбиваются на пять пар...

Общая и профессиональная культура педагога: сущность, специфика, взаимосвязь Педагогическая культура- часть общечеловеческих культуры, в которой запечатлил духовные и материальные ценности образования и воспитания, осуществляя образовательно-воспитательный процесс...

Устройство рабочих органов мясорубки Независимо от марки мясорубки и её технических характеристик, все они имеют принципиально одинаковые устройства...

Ведение учета результатов боевой подготовки в роте и во взводе Содержание журнала учета боевой подготовки во взводе. Учет результатов боевой подготовки - есть отражение количественных и качественных показателей выполнения планов подготовки соединений...

Билиодигестивные анастомозы Показания для наложения билиодигестивных анастомозов: 1. нарушения проходимости терминального отдела холедоха при доброкачественной патологии (стенозы и стриктуры холедоха) 2. опухоли большого дуоденального сосочка...

Сосудистый шов (ручной Карреля, механический шов). Операции при ранениях крупных сосудов 1912 г., Каррель – впервые предложил методику сосудистого шва. Сосудистый шов применяется для восстановления магистрального кровотока при лечении...

Трамадол (Маброн, Плазадол, Трамал, Трамалин) Групповая принадлежность · Наркотический анальгетик со смешанным механизмом действия, агонист опиоидных рецепторов...

Studopedia.info - Студопедия - 2014-2026 год . (0.011 сек.) русская версия | украинская версия