Пользовательские условные логические операторы — КиберПедия 

Типы сооружений для обработки осадков: Септиками называются сооружения, в которых одновременно происходят осветление сточной жидкости...

Биохимия спиртового брожения: Основу технологии получения пива составляет спиртовое брожение, - при котором сахар превращается...

Пользовательские условные логические операторы

2017-10-16 308
Пользовательские условные логические операторы 0.00 из 5.00 0 оценок
Заказать работу

Если операнды && или || имеют типы, в которых объявляются применимые пользовательские операторы operator & или operator |, то должны выполняться оба следующих условия, где T является типом, в котором объявляется выбранный оператор.

· Типом возвращаемого значения и типом каждого параметра выбранного оператора должен быть T. Другими словами, оператор должен вычислять операцию логического AND или логического OR для двух операндов типа T и должен возвращать результат типа T.

· T должен содержать объявления операторов operator true и operator false.

Если какое-либо из этих условий не выполняется, возникает ошибка времени привязки. Иначе операция && или || вычисляется путем объединения пользовательских операторов operator true и operator false с выбранным пользовательским оператором:

· Операция x && y вычисляется как T.false(x)? x: T.&(x, y), где T.false(x) является вызовом оператора operator false, объявленного в T, а T.&(x, y) является вызовом выбранного оператора operator &. Другими словами, сначала вычисляется x и для результата вызывается operator false, чтобы определить, имеет ли x значение false. Затем, если x имеет значение false, результатом операции становится значение, ранее вычисленное для x. Иначе вычисляется y и выбранный оператор operator & вызывается для ранее вычисленного значения для x и вычисленного значения y, чтобы получить результат операции.

· Операция x || y вычисляется как T.true(x)? x: T.|(x, y), где T.true(x) является вызовом оператора operator true, объявленного в T, а T.|(x, y) является вызовом выбранного оператора operator |. Другими словами, сначала вычисляется x и для результата вызывается operator true, чтобы определить, имеет ли x значение true. Затем, если x имеет значение true, результатом операции становится значение, ранее вычисленное для x. Иначе вычисляется y и выбранный оператор operator | вызывается для ранее вычисленного значения для x и вычисленного значения y, чтобы получить результат операции.

В обеих этих операциях выражение в x вычисляется только один раз, а выражение в y либо не вычисляется, либо вычисляется ровно один раз.

Пример типа, реализующего операторы operator true и operator false, см. в разделе §11.4.2.

Оператор слияния с NULL

Оператор?? называется оператором слияния с NULL.

null-coalescing-expression:
conditional-or-expression
conditional-or-expression?? null-coalescing-expression

В выражении слияния с NULL вида a?? b требуется, чтобы a имело обнуляемый или ссылочный тип. Если a не равно значению NULL, результатом выражения a?? b является a; в противном случае результатом является b. В операции вычисление b происходит, только если a равно NULL.

Оператор слияния с null имеет правую ассоциативность, что означает, что операции группируются справа налево. Например, выражение вида a?? b?? c вычисляется как a?? (b?? c). В общем случае выражение вида E1?? E2??...?? EN возвращает первый операнд, не равный NULL, или NULL, если все операнды равны NULL.

Тип выражения a?? b зависит от того, какие неявные преобразования доступны с операндами. В порядке предпочтения тип a?? b равен A0, A или B, где A является типом a (при условии, что у a есть тип), B является типом b (при условии, что у b есть тип), а A0 является базовым типом A, если A является обнуляемым типом, либо равен типу A в противном случае. В частности, a?? b обрабатывается следующим образом.

· Если A существует и не является обнуляемым типом или ссылочным типом, возникает ошибка времени компиляции.

· Если b является динамическим выражением, то тип результата будет dynamic. Во время выполнения сначала вычисляется a. Если a не равно NULL, для a выполняется преобразование в динамический тип, и это становится результатом. Иначе вычисляется b и это становится результатом.

· Иначе, если A существует и является обнуляемым типом и существует неявное преобразование из b в A0, то типом результата будет A0. Во время выполнения сначала вычисляется a. Если a не равно NULL, для a выполняется снятие упаковки до типа A0 и это становится результатом. Иначе вычисляется b и преобразуется в тип A0 и это становится результатом.

· Иначе, если существует A и существует неявное преобразование из b в A, то типом результата будет A. Во время выполнения сначала вычисляется a. Если a не равно NULL, a становится результатом. Иначе вычисляется b и преобразуется в тип A и это становится результатом.

· Иначе, если b имеет тип B и существует неявное преобразование из a в B, то типом результата будет B. Во время выполнения сначала вычисляется a. Если a не равно NULL, для a выполняется снятие упаковки до типа A0 (если только A существует и является обнуляемым), оно преобразуется в тип B и это становится результатом. Иначе вычисляется b и это становится результатом.

· Иначе a и b являются несовместимыми и возникает ошибка времени компиляции.

Условный оператор

Оператор?: называется условным оператором. Иногда его также называют тернарным оператором.

conditional-expression:
null-coalescing-expression
null-coalescing-expression? expression: expression

В условном выражении вида b? x: y сначала вычисляется условие b. Затем, если b равно true, вычисляется x и это становится результатом операции. Иначе вычисляется y и это становится результатом операции. В условном выражении никогда не выполняется вычисление и x, и y.

Условный оператор имеет правую ассоциативность, что означает, что операции группируются справа налево. Например, выражение вида a? b: c? d: e вычисляется как a? b: (c? d: e).

Первый операнд оператора?: должен быть выражением с типом, который можно неявно преобразовать в тип bool, или выражением типа, в котором реализован оператор operator true. Если не выполняется ни одно из этих требований, то возникает ошибка времени компиляции.

Второй и третий операнды, x и y, оператора?: задают тип условного выражения.

· Если x имеет тип X, а y имеет тип Y, то

o Если из X в Y существует неявное преобразование (§6.1), а из Y в X не существует, то типом условного выражения является Y.

o Если из Y в X существует неявное преобразование (§6.1), а из X в Y не существует, то типом условного выражения является X.

o Иначе тип выражения определить нельзя, и возникает ошибка времени компиляции.

· Если только один из x и y имеет тип, и оба x и y могут быть неявно преобразованы в этот тип, то он является типом условного выражения.

· Иначе тип выражения определить нельзя, и возникает ошибка времени компиляции.

Во время выполнения обработка условного выражения вида b? x: y включает следующие этапы.

· Сначала вычисляется b и определяется значение b типа bool:

o Если существует неявное преобразование из типа b в bool, то для получения значения типа bool выполняется это неявное преобразование.

o В противном случае для получения значения типа bool вызывается оператор operator true, определенный типом b.

· Если полученное на предыдущем этапе значение типа bool равно true, то x вычисляется и преобразуется в тип условного выражения и это становится результатом условного выражения.

· Иначе y вычисляется и преобразуется в тип условного выражения и это становится результатом условного выражения.

Выражения анонимных функций

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

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

lambda-expression:
asyncopt anonymous-function-signature => anonymous-function-body

anonymous-method-expression:
asyncopt delegate explicit-anonymous-function-signatureopt block

anonymous-function-signature:
explicit-anonymous-function-signature
implicit-anonymous-function-signature

explicit-anonymous-function-signature:
(explicit-anonymous-function-parameter-listopt)

explicit-anonymous-function-parameter-list:
explicit-anonymous-function-parameter
explicit-anonymous-function-parameter-list, explicit-anonymous-function-parameter

explicit-anonymous-function-parameter:
anonymous-function-parameter-modifieropt type identifier

anonymous-function-parameter-modifier:
ref
out

implicit-anonymous-function-signature:
(implicit-anonymous-function-parameter-listopt)
implicit-anonymous-function-parameter

implicit-anonymous-function-parameter-list:
implicit-anonymous-function-parameter
implicit-anonymous-function-parameter-list, implicit-anonymous-function-parameter

implicit-anonymous-function-parameter:
identifier

anonymous-function-body:
expression
block

Оператор => имеет такой же приоритет, как и присваивание (=) и обладает правой ассоциативностью.

Анонимная функция с модификатором async является асинхронной функцией, которая следует правилам, описанным в разделе §10.14.

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

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

(param) => expr

можно сократить до:

param => expr

Список параметров анонимной функции в виде выражения анонимного метода является необязательным. Если они заданы, то параметры должны быть явно типизированы Если они не задаются, то анонимную функцию можно преобразовать в делегат с любым списком параметров, не содержащих параметров out.

Тело блока анонимной функции достижимо (§8.1), если анонимная функция не расположена внутри недостижимого оператора.

Ниже приведены некоторые примеры анонимных функций.

x => x + 1 // Implicitly typed, expression body

x => { return x + 1; } // Implicitly typed, statement body

(int x) => x + 1 // Explicitly typed, expression body

(int x) => { return x + 1; } // Explicitly typed, statement body

(x, y) => x * y // Multiple parameters

() => Console.WriteLine() // No parameters

async (t1,t2) => await t1 + await t2 // Async

delegate (int x) { return x + 1; } // Anonymous method expression

delegate { return 1 + 1; } // Parameter list omitted

Поведение лямбда-выражений и выражений анонимных методов совпадает за исключением следующих моментов:

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

· лямбда-выражения позволяют опускать и выводить типы параметров, тогда как в выражениях анонимных методов типы параметров должны быть указаны явно.

· Тело лямбда-выражения может быть выражением или блоком оператора, тогда как тело выражения анонимного метода должно быть блоком оператора.

· Только для лямбда-выражений существуют преобразования в совместимые деревья выражений (§4.6).

Сигнатуры анонимных функций

Необязательная подпись анонимной функции задает названия и (необязательно) имена формальных параметров анонимной функции. Область действия параметров анонимной функции — это тело анонимной функции. (§3.7) Вместе со списком параметров (если он предоставлен) тело анонимного метода задает пространство объявления (§3.3). Таким образом, если имя параметра анонимной функции совпадает с именем локальной переменной, локальной константы или параметра, область действия которого включает выражение анонимного метода или лямбда-выражение, то будет возникать ошибка времени компиляции.

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

Обратите внимание, что сигнатура анонимной функции не может включать атрибуты или массив параметров. Тем не менее сигнатура анонимной функции может быть совместима с типом делегата, список параметров которого содержит массив параметров.

Обратите внимание, что преобразование в тип дерева выражения, даже если он совместим, может привести к сбою во время компиляции (§4.6).

Тела анонимных функций

Тело (выражение или блок) анонимной функции должно удовлетворять следующим правилам.

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

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

· Если типом this является тип структуры, то при обращении в теле к this возникает ошибка времени выполнения. Это так при явном доступе (как в случае this.x) и при неявном (ср. x, где x является членом экземпляра структуры). Это правило просто запрещает такой доступ и не влияет на то, будет ли при поиске члена найден член структуры.

· В теле можно обращаться к внешним переменным (§7.15.5) анонимной функции. При доступе к внешней переменной будет сформирована ссылка на экземпляр переменной, активной во время вычисления лямбда-выражения или выражения анонимного метода (§7.15.6).

· При наличии в теле оператора goto, break или continue, назначением которого является расположение вне тела или внутри тела содержащейся анонимной функции, будет возникать ошибка времени компиляции.

· Оператор return в теле возвращает управление из вызова ближайшей включающей анонимной функции, а не из включающей функции-члена. Выражение, указанное в операторе return, должно быть неявно преобразуемым в возвращаемый тип типа делегата или типа дерева выражений, в который преобразуется ближайшее включающее лямбда-выражение или выражение анонимного метода (§6.5).

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

Разрешение перегрузки

Анонимные функции в списке аргументов участвуют в выводе типа и разрешении перегрузки. Подробные правила см. в разделах §7.5.2 и §7.5.3.

В следующем примере демонстрируется результат использования анонимных функций при разрешении перегрузки

class ItemList<T>: List<T>
{
public int Sum(Func<T,int> selector) {
int sum = 0;
foreach (T item in this) sum += selector(item);
return sum;
}

public double Sum(Func<T,double> selector) {
double sum = 0;
foreach (T item in this) sum += selector(item);
return sum;
}
}

Класс ItemList<T> содержит два метода Sum. У каждого метода есть аргумент selector, который извлекает значение для суммирования из списка элементов. Извлеченное значение может иметь тип int или double, и сумма в результате также будет иметь тип int или double.

Методы Sum можно, например, использовать для вычисления сумм из списка строк с деталями заказов.

class Detail
{
public int UnitCount;
public double UnitPrice;
...
}

void ComputeSums() {
ItemList<Detail> orderDetails = GetOrderDetails(...);
int totalUnits = orderDetails.Sum(d => d.UnitCount);
double orderTotal = orderDetails.Sum(d => d.UnitPrice * d.UnitCount);
...
}

В первом вызове 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.


Поделиться с друзьями:

Биохимия спиртового брожения: Основу технологии получения пива составляет спиртовое брожение, - при котором сахар превращается...

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

Типы оградительных сооружений в морском порту: По расположению оградительных сооружений в плане различают волноломы, обе оконечности...

Адаптации растений и животных к жизни в горах: Большое значение для жизни организмов в горах имеют степень расчленения, крутизна и экспозиционные различия склонов...



© cyberpedia.su 2017-2024 - Не является автором материалов. Исключительное право сохранено за автором текста.
Если вы не хотите, чтобы данный материал был у нас на сайте, перейдите по ссылке: Нарушение авторских прав. Мы поможем в написании вашей работы!

0.047 с.