Операторы равенства делегатов
Каждый тип делегата неявно предоставляет следующие стандартные операторы сравнения:
bool operator ==(System.Delegate x, System.Delegate y);
bool operator !=(System.Delegate x, System.Delegate y);
Два делегата считаются равными, если выполняется одно из следующих условий.
· Если один из экземпляров делегата равен null, то они равны, только они оба равны null.
· Если делегаты имеют разный тип во время выполнения, то они не могут быть равны.
· Если у обоих экземпляров делегата есть список вызова (§15.1), то они равны, только если их списки вызова имеют одну длину и каждая запись в списке вызова одного делегата равна (в соответствии с определением ниже) соответствующей записи по порядку в списке вызова другого делегата.
Равенство записей списка вызова определяется следующими правилами.
· Если две записи списка вызова ссылаются на один статический метод, то записи равны.
· Если две записи списка вызова ссылаются на один нестатический метод одного целевого объекта (определяется операторами равенства ссылочных значений), то записи равны.
· Записи списка вызова, полученные при вычислении семантически идентичных выражений анонимных функций с одинаковым (возможно пустым) набором захваченных внешних экземпляров переменных могут (но не обязательно) быть равны.
Операторы равенства и значение NULL
Операторы == и != допускают, что один операнд был значением обнуляемого типа, а второй литералом null, даже если для операции не существует стандартного или пользовательского оператора (обычного или с нулификацией).
Для операции одного из видов
x == null null == x x != null null != x
где x является выражением обнуляемого типа, если при разрешении перегрузки операторов (§7.2.4) не удается найти применимый оператор, то результат вычисляется на основании свойства HasValue для x. В частности, первые два вида операции преобразуются в!x.HasValue, а два последних вида преобразуются в x.HasValue.
Оператор is
Оператор is используется для динамической проверки, можно ли сравнивать тип объекта во время выполнения с указанным типом. Результат операции E is T, где E — это выражение, а T — тип, является логическим значением, которое указывает, можно ли провести преобразование E в тип T с помощью преобразования ссылки, преобразования упаковки или преобразования отмены упаковки. После замены всех параметров типа на аргументы типа операция вычисляется следующим образом.
· Если E является анонимной функцией, возникает ошибка времени компиляции
· Если E является группой методов или литералом null или если E имеет ссылочный или обнуляемый и значение E равно NULL, то результат равен false.
· Иначе пусть D обозначает динамический тип E следующим образом.
o Если E имеет ссылочный тип, D является типом времени выполнения для экземпляра, на который ссылается E.
o Если E имеет обнуляемый тип, D является базовым типом этого обнуляемого типа.
o Если E имеет необнуляемый тип значения, D имеет тип E.
· Результат операции зависит от D и T следующим образом.
o Если T имеет ссылочный тип, то результат равен true, если D и T имеют одинаковый тип, если D имеет ссылочный тип и существует неявное преобразование ссылки из D в T или если D имеет тип значения и существует преобразование упаковки из D в T.
o Если T имеет обнуляемый тип, результат равен true, если D является базовым типом T.
o Если T является необнуляемым типом значения, результат равен true, если D и T имеют одинаковый тип
o Иначе результат равен false.
Обратите внимание, что пользовательские преобразования в операторе is не учитываются.
Оператор as
Оператор as используется для явного преобразования значения в указанный ссылочный тип или обнуляемый тип. В отличие от выражения приведения типа (§7.7.6) оператор as никогда не вызывает исключения. Вместо этого, если указанное преобразование невозможно, возвращается значение null.
В операции вида E as T E должно быть выражением, а T должен быть ссылочным типом, параметром типа, который является ссылочным типом, или обнуляемым типом. Кроме того, должно выполняться, по крайней мере, одно из следующих условий. В противном случае будет возникать ошибка времени компиляции.
· Из E в T существует преобразование идентификации (§6.1.1), неявное преобразование обнуляемых типов (§6.1.4), неявное преобразование ссылочных типов (§6.1.6), преобразование упаковки (§6.1.7), явное преобразование обнуляемых типов (§6.2.3), явное преобразование ссылочных типов (§6.2.4) и преобразование отмены упаковки (§6.2.5).
· Тип E или T является открытым.
· E является литералом null.
Если тип времени компиляции E не является dynamic, операция E as T дает такой же результат, как и
E is T ? (T)(E) : (T)null
за исключением того, что E вычисляется только один раз. Компилятор может проводить оптимизацию операции E as T, чтобы при ее обработке выполнялась только одна динамическая проверка типа в отличие от двух динамических проверок типа в расширении выше.
Если тип времени компиляции E является dynamic, то, в отличие от оператора приведения, оператор as не имеет динамической привязки (§7.2.2). Таким образом, развертывание в данном случае будет следующим:
E is T ? (T)(object)(E) : (T)null
Обратите внимание, что некоторые преобразования, например пользовательские преобразования нельзя использовать с оператором as и вместо них следует использовать выражения приведения типа.
В этом примере
class X
{
public string F(object o) {
return o as string; // OK, string is a reference type
}
public T G<T>(object o) where T: Attribute {
return o as T; // Ok, T has a class constraint
}
public U H<U>(object o) {
return o as U; // Error, U is unconstrained
}
}
параметр T для G имеет ссылочный тип, поскольку у него есть ограничение класса. Напротив, параметр типа U для H не имеет ссылочного типа, поэтому использование оператора as в H запрещено.
Логические операторы
Операторы &, ^ и | называются логическими операторами.
and-expression:
equality-expression
and-expression & equality-expression
exclusive-or-expression:
and-expression
exclusive-or-expression ^ and-expression
inclusive-or-expression:
exclusive-or-expression
inclusive-or-expression | exclusive-or-expression
Если операнд логического оператора имеет тип dynamic во время компиляции, то он динамически связан (§7.2.2). В этом случае тип времени компиляции выражения — dynamic, а разрешение, приведенное ниже, будет иметь место во время выполнения при использовании типа времени выполнения тех операндов, которые имеют тип dynamic во время компиляции.
Для операции вида x op y, где op является одним из логических операторов, чтобы выбрать конкретную реализацию оператора, применяется разрешение перегрузки (§7.3.4). Операнды преобразуются в типы параметров выбранного оператора, а тип результата является типом возвращаемого значения этого оператора.
Стандартные логические операторы описываются в следующих разделах.