, то ему можно присвоить значение только в конструкторе.
Перезагрузка операторов
Перезагрузка операторов происходит в C# и в C++ аналогично, но существуют небольшие различия. Например, C++ допускает перезагрузку большинства своих операторов. C# имеет больше ограничений. Для многих составных операторов C# автоматически определяет значение оператора из значений составляющих операторов, т.е. там, где C++ допускает прямую перезагрузку. Например, в C++ перезагружается
+
и отдельно
+=
.
В C# можно перезагрузить только
+
. Компилятор всегда будет использовать перезагруженную версию
+
, чтобы автоматически определить значение
+=
для этого класса или структуры.
Следующие операторы могут перезагружаться в C# также, так и в C++:
□ Бинарные арифметические операторы
+
,
–
,
*
,
/
,
%
□ Унарные операторы
++
и
– -
(только префиксная форма)
□ Операторы сравнения
!=
,
==
,
<
,
<=
,
>=
□ Побитовые операторы
&
,
|
,
~
,
^
,
!
□ Булевы значения
true
и
false
Следующие операторы, перезагружаемые в C++, нельзя перезагружать в C#.
□ Арифметические операторы присваивания
*=
,
/=
,
+=
,
– =
,
%=
. (Они определяются компилятором из соответствующих арифметических операторов и оператора присваивания, который не может перезагружаться.) Постфиксные операторы увеличения на единицу. Они определяются компилятором из перезагруженных версий соответствующих префиксных операторов. (Реализуются с помощью вызова соответствующей перезагруженной версии префиксного оператора, но возвращают первоначальное значение операнда вместо нового значения.)
□ Операторы побитового присваивания
&=
,
|
=,
^=
,
>>=
и
<<=
.
□ Булевы операторы
&&
,
||
. (Они определяются компилятором из соответствующих побитовых операторов.)
□ Оператор присваивания
=
. Значение этого оператора в C# фиксировано.
Существует также ограничение в том, что операторы сравнения должны перезагружаться парами, другими словами, при перезагрузке
==
необходимо перезагрузить также
!=
и наоборот. Аналогично, если перезагружается один из операторов
<
и
<=
, то необходимо перезагрузить оба оператора и так же для
>
и
>=
. Причина этого состоит в необходимости обеспечения согласованной поддержки для любых типов данных базы данных, которые могут иметь значение
null
и для которых поэтому, например,
==
не обязательно имеет результат, противоположный
!=
.
После определения того, что оператор, который требуется перезагрузить, является таким, который можно перезагрузить в C#, синтаксис для реального определения перезагруженной версии значительно проще, чем соответствующий синтаксис в C++. Единственный момент, о котором необходимо помнить при перегрузке операторов C#, состоит в том, что они всегда должны объявляться как статические члены класса. Это противоположно ситуации в C++, где можно определить свои операторы либо как статические члены класса, как член экземпляра класса (но беря на один параметр меньше), либо как функцию, которая не является членом класса вообще.
Причина того, что определение перезагруженных версий операторов настолько проще в C#, не имеет на самом деле ничего общего с самими перезагруженными версиями операторов. Это связано со способом, которым осуществляется управление памятью в C#. Определение перезагруженных версий операторов в C++ является областью, которая заполнена ловушками, Рассмотрим, например, попытку перезагрузить оператор
сложения для класса в C++. (Предполагается для этого,
что
CMyClass имеет член
x
и сложение экземпляров означает сложение членов
x
.). Код может выглядеть следующим образом (предполагается, что перезагруженная версия является явной вставкой кода):
и передаются по ссылке, чтобы обеспечить оптимальную производительность. Это само по себе не слишком плохо. Однако теперь для возвращения результата, необходимо создать временный экземпляр
CMyClass
внутри перезагруженной версии оператора. Конечная инструкция
return Result
выглядит безопасной, но она будет компилироваться только в том случае, если доступен оператор присваивания для копирования
Result
из функции.
Это само по себе является нетривиальной задачей, так как если ссылки используются неправильно при определении, то очень легко случайно определить ссылку, которая рекурсивно вызывает себя, пока не будет получено переполнение стека. Перезагрузка операторов в C++ является задачей для опытных программистов. Нетрудно видеть, почему компания Microsoft решила сделать некоторые операторы неперезагружаемыми в C#.
В C# практика будет другой. Здесь нет необходимости явно передавать по ссылке, так как классы C# являются ссылочными переменными в любом случае (а для структур передача по ссылке снижает производительность). И возвращение значения является легкой задачей. Будет ли это класс или структура, надо просто вернуть значение временного результата, а компилятор C# гарантирует, что в результате будут скопированы либо поля-члены (для типов данных значений), либо адреса (для ссылочных типов). Единственный недостаток заключается в том, что нельзя использовать ключевое слово
const
, чтобы получить дополнительную проверку компилятора, которая определяет, изменяет или нет перезагруженная версия оператора параметры класса. Также C# не предоставляет улучшения производительности подставляемых функций, как происходит в C++.