Булевские операции

Некоторые типы могут принимать участие в булевских выражениях проверки, таких как встречающиеся внутри скобок блока i f или внутри тернарной операции ? :. Чтобы это работало, имеются две альтернативы. Первая заключается в том, что можно реализовать две операции преобразования, известные как operator true и operator false. Они должны быть реализованы в паре, чтобы позволить комплексному числу (типу Complex) участвовать в булевских выражениях проверки.

Рассмотрим следующую модификацию типа Complex, которая позволяет использовать его в выражениях; здесь значение (О, О) означает false, а все остальное — true:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
using System;
public struct Complex
{
public Complex ( double real, double imaginary )  {
this.real = real;
this.imaginary = imaginary;
}
// Переопределение System.Object
public override string ToString()  {
return String.Format( "({0},  {1})",
real,
imaginary ) ;
}
public double Magnitude {
get {
return Math.Sqrt( Math.Pow(this.real, 2) +
Math.Pow(this.imaginary, 2)  );
}
}
public static bool operator true ( Complex с )  {
return (c.real != 0)   ||   (c.imaginary != 0) ;
}
public static bool operator false( Complex с )  {
return (c.real == 0) && (c.imaginary == 0) ;
}
// Остальные методы опущены для ясности,
private double real;
private double imaginary;
}
public class EntryPoint {
static void Main()  {
Complex cpxl = new Complex ( 1.0, 3.0 );
if ( cpxl )  {
Console.WriteLine( "cpxl равно true" );
} else {
Console.WriteLine( "cpxl равно false" );
}
Complex cpx2 = new Complex ( 0, 0 );
Console.WriteLine( "cpx2 равно {0}", cpx2 ? "true" : "false" );
}

Здесь реализованы две операции для применения к типу Complex проверок на предмет равенства true и false. Обратите внимание на несколько причудливый синтаксис. Он выглядит почти так же, как в обычных операциях, за исключением того, что типом возврата является bool. Зачем это нужно — не совсем понятно, поскольку указать какой-то другой тип возврата для этих операций все равно не удастся.

Если все-таки попробовать это сделать, то компилятор немедленно сообщит, что единственным допустимым типом возврата для operator true и operator false является bool. Тем не менее, тип возврата должен быть указан. Также обратите внимание, что эти операции нельзя пометить как explicit или implicit, потому что они не являются операциями преобразования. После определения этих двух операций в типе можно использовать экземпляры Complex в булевских выражениях проверки, как показано в методе Main.

В качестве альтернативы можно реализовать преобразование к типу bool и получить тот же результат. Обычно для простоты использования эта операция реализуется неявно. Рассмотрим модифицированную форму предыдущего примера с использованием неявной операции преобразования к bool вместо operator true и operator false:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
using System;
public struct Complex
{
public Complex ( double real, double imaginary )  {
this.real = real;
this.imaginary = imaginary;
}
// Переопределение System.Object
public override string ToString ()  {
return String.Format( " ({0 },  {1})",
real,
imaginary ) ;
}
public double Magnitude {
get {
return Math.Sqrt ( Math.Pow(this.real, 2) + Math.Pow(this.imaginary, 2)  );
}
}
public static implicit operator bool ( Complex с )  {
return (c.real != 0)   ||   (c.imaginary != 0) ;
}
// Остальные методы опущены для ясности,
private double real;
private double imaginary;
}
public class EntryPoint {
static void Main()  {
Complex cpxl = new Complex ( 1.0, 3.0 );
if ( cpxl )  {
Console.WriteLine ( "cpxl равно true" );
} else {
Console.WriteLine ( "cpxl равно false" );
}
Complex cpx2 = new Complex ( 0, 0 );
Console.WriteLine ( "cpx2 равно {0}", cpx2 ? "true" : "false" );
}

Конечный результат выглядит так же, как в предыдущем примере. Теперь может возникнуть вопрос, а зачем вообще реализовывать operator true и operator false вместо простой неявной операции преобразования к bool? Ответ зависит от того, допустимо ли для заданного типа преобразование в тип bool. В последней форме, где реализована неявная операция преобразования, следующий оператор будет корректным:

1
bool f = cpxl;

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

Существует следующее эмпирическое правило: предусматривайте только те операции, которые действительно необходимы для выполнения работы, и не более. Если все, что нужно от типа — в данном случае Complex — это возможность участия в булевских выражениях проверки, реализуйте только operator true и operator false. Не реализуйте операцию неявного преобразования в bool, если только действительно не нуждаетесь в ней.

Если окажется, что она все-таки нужна и должна быть реализована, тогда не понадобится реализовывать operator true и operator false, потому что они будут избыточны.

Если представлены все три операции, то компилятор будет использовать операцию неявного преобразования в bool вместо operator true и operator false, поскольку вызов первой не является более эффективным, чем остальных, предполагая, что закодированы они одинаково.

Вы можете следить за любыми ответами на эту запись через RSS 2.0 ленту. Вы можете оставить ответ, или trackback с вашего собственного сайта.

Оставьте отзыв

XHTML: Вы можете использовать следующие теги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

 
Rambler's Top100