неперезагружаемыми в C#.

В C# практика будет другой. Здесь нет необходимости явно передавать по ссылке, так как классы C# являются ссылочными переменными в любом случае (а для структур передача по ссылке снижает производительность). И возвращение значения является легкой задачей. Будет ли это класс или структура, надо просто вернуть значение временного результата, а компилятор C# гарантирует, что в результате будут  скопированы либо поля-члены (для типов данных значений), либо адреса (для ссылочных типов). Единственный недостаток заключается в том, что нельзя использовать ключевое слово const, чтобы получить дополнительную проверку компилятора, которая определяет, изменяет или нет перезагруженная версия оператора параметры класса. Также C# не предоставляет улучшения производительности подставляемых функций, как происходит в C++.

static MyClass operator+(MyClass lhs, CMyClass rhs) {

 MyClassResult = new MyClass();

 Result.x = lhs.x + rhs.x;

 return Result;

}

Индексаторы

C# cтрого не разрешает перезагружать []. Однако он позволяет определить так называемые индексаторы (indexer) класса, что обеспечивает такой же результат.

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

class MyClass {

 public long this[int x] {

  get {

   // код для получения элемента

  }

  set {

   // код для задания элемента, например X = value;

  }

 }

 // и т.д.

Код внутри блока get выполняется всякий раз, когда Mine[x] стоит с правой стороны выражения (при условии, что выражение Mine является экземпляром MyClass и x будет int), в то время как блок set выполняется только тогда, когда Mine[x] указывается с левой стороны выражения. Блок set ничего не может вернуть и использует ключевое слово value для указания величины, которая появится с правой стороны выражения. Блок get должен вернуть тот же тип данных, который имеет индексатор.

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

Определенные пользователем преобразования типов данных

Так же как для индексаторов и [], C# формально не рассматривает () как оператор, который может перезагружаться, однако C# допускает определяемые пользователем преобразования типов данных, которые имеют тот же результат. Например, предположим, что имеются два класса (или структуры) с именами MySource и MyDest и необходимо определить преобразование типа из MySource в MyDest. Синтаксис этого выглядит следующим образом:

public static implicite operator MyDest(MySource Source) {

 // код для выполнения преобразования. Должен возвращать экземпляр MyDest

}

Преобразование типа данных определяется как статический член класса MyDest или класса MySource. Оно должно также объявляться любо как implicit, либо как explicit. Если преобразование объявлено как implicit, то оно используется неявно:

MySource Source = new MySource();

MyDest Dest = MySource;

Если преобразование объявлено как explicit, то оно может использоваться только явным образом:

MySource Source = new MySource();

MyDest Dest = (MyDest)MySource;

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

Так же как и в C++, если компилятор C# встречается с запросом преобразования между типами данных, для которых не существует прямого преобразования типов, он будет стараться найти 'лучший' способ, используя доступные методы преобразования типов. Существуют те же вопросы, что и в C++, в отношении интуитивной ясности преобразований типов данных, а также в том, что различные пути получения преобразования не создают несовместимых результатов.

C# не позволяет определить преобразования типов данных между классами, которые являются производными друг друга. Такие преобразования уже доступны — неявно из производного класса в базовый класс и явно из базового класса в производный.

Отметим, что если попробовать выполнить преобразование ссылки базового класса в ссылку производного класса, и при этом рассматриваемый объект не является экземпляром производного класса (или какого-нибудь производного из него), то будет порождаться (генерироваться) исключение. В C++ нетрудно преобразовать указатель на объект в 'неправильный' класс объектов. Это просто невозможно в C# с помощью ссылок. По этой причине преобразование типов в C# считается более безопасным, чем в C+ +.

// пусть MyDerivedClass получен из MyBaseClass

MyBaseClass MyBase = new MyBaseClass();

MyDerivedClass MyDerived = (MyDerivedClass) MyBase; // это приведет

 // к порождению исключения

Если нежелательно преобразовывать что-то в производный класс, но нежелательно также, чтобы генерировалось исключение, можно применить ключевое слово as. При использовании as, если преобразование отказывает, будет возвращаться null.

// пусть MyDerivedClass получен из MyBaseClass

MyBaseClass MyBase = new MyBaseClass();

MyDerivedClass MyDerived as (MyDerivedClass)MyBase; // это

                                                    // возвратит null

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

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

Отметить Добавить цитату