Чтение онлайн

ЖАНРЫ

C# для профессионалов. Том II

Ватсон Карли

Шрифт:

□ 

struct
не является базой для класса

□ Хотя

struct
может oбъявлять конструкторы, эти конструкторы должны получать не меньше одного аргумента.

□ Члены

struct
не могут иметь инициализаторов.

□ Возможно создание экземпляра

struct
без использования ключевого слова
new
.

□ 

struct
может реализовывать интерфейсы.

Атрибуты используются со структурами чтобы добавить им дополнительную мощь и гибкость. Атрибут

StructLayout
в пространстве имен
System.Runtime.InteropServices
, например, применяется для определения компоновки полей в
struct
.
Это свойство подходит и для создания структуры, аналогичной по функциональности
union
в С/C++,
union
является типом данных, члены которого находятся в одном блоке памяти. Он может использоваться для хранения значений различных типов в одном блоке памяти.
union
годится и в том случае, когда неизвестно, каким будет тип полученных значений. Конечно, никакого рeaльного преобразования не происходит, фактически не существует никакие базовых проверок допустимости данных. Один и тот же набор битов интерпретируется различным образом. Рассмотрим пример того, как
union
создается с помощью
struct
:

[StructLayout(LayoutKind.Explicit)]

public struct Variant {

 [FieldOffset(0)] public int intVal;

 [FieldOffset(0)] public string stringVal;

 [FieldOffset(0)] public decimal decVal;

 [FieldOffset(0)] public float floatVal;

 [FieldOffset(0)] public char charVal;

}

Атрибут

FieldOffset
, применяемый к полям, используется для задания физического расположения указанного поля. Задание начальной точки каждого поля как 0 гарантирует, что любое сохранение данных в одном поле перезапишет практически любые данные, которые там находятся. Отсюда следует, что общий размер полей равен размеру наибольшего поля, в данном случае
decimal
.

Ссылочные типы

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

extends
и
implements
. Оператор двоеточия (
:
) заменяет оба ключевых слова Java, и, как было показано ранее, директива
using
аналогична инструкции Java
import
. Строки тоже используются одинаково в C# и Java. C# вводит также новый тип ссылочного типа называемого делегатом. Делегаты представляют безопасную, с точки зрения типов, версию указателей функций. Они будут рассмотрены позже в этой главе.

Массивы

C# поддерживает "неровные" массивы и добавляет многомерные массивы. Может сбить с толку то, что Java не делает между ними различий:

int [] х = new int[20]; // как в Java, только [] должны следовать

// за типом

int [,] у = new int[12, 3]; // то же самое, что int у[] [] = new

// int[12][3];

int[][] z = new int[5][]; // то же самое, что и int x[][] = new

// int [5][];

Примечание. Ключевое слово

int[]
обозначает реальный тип данных, поэтому синтаксически оно записывается таким образом. Нельзя, как в Java, поместить двойные скобки перед или после переменной. Прежде чем перейти к дополнительным деталям о ссылочных типах и обсуждению таких концепции, как классы, давайте поговорим немного об операциях. Следующий раздел посвящен операторам.

Операторы

В Java конечный результат применения оператора к одному или нескольким операндам является новым значением для одного или нескольких вовлеченных операндов. C# предоставляет аналогичную

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

Присваивание

C# и Java используют знак

=
для присваивания значений переменным. В C#, как и в Java, переменные присвоенные объектам содержат только ссылку или "адрес" на этот объект, а не сам объект. Присваивание одной ссылочной переменной другой таким образом просто копирует "адрес" в новую переменную. Следовательно обе переменные теперь имеют возможность делать ссылку на один объект. Эту концепцию легко проиллюстрировать с помощью примера. Рассмотрим класс
ExOperators
, приведенный ниже:

public class EXOperators {

 internal int р;

 public EXOperators {}

 public static void Main {

ExOperators one = new EXOperators;

one.p = 200;

EXOperators two;

two = one;

two.p = 100;

Console.WriteLine(two.p);

Console.WriteLine(one.p);

 }

}

Пока проигнорируем ключевое слово

internal
перед переменной
р
. Оно является модификатором доступа, который будет рассмотрен далее в этой главе. Достаточно сказать, что оно делает переменную
р
видимой для метода
Main
. Приведенный выше пример создает экземпляр объекта
EXOperators
и сохраняет его в локальной переменной
one
. Эта переменная затем присваивается другой переменной —
two
. После этого значение
p
в объекте, на который ссылается
two
, изменяется на 100. В конце выводится значение переменной
p
в обоих объектах. Компиляция и выполнение этого даст результат 100 дважды, указывая, что изменение
two.р
было тем же самым, что изменение значения
one.р
.

Сравнение

Операторы сравнения обычно совпадают по форме и функциональности в обоих языках. Четырьмя основными операторами являются

<
— меньше, чем,
>
— больше, чем,
<=
меньше или равно и
>=
— больше или равно.

Чтобы определить, принадлежит ли объект заданному классу или любому из классов предков, Java использует оператор

instanceof
. Простой пример этого приведен в листинге ниже:

String у = "a string";

Object х = у;

if (х instanceof String) {

 System.out.println("х is a string");

}

В C# эквивалентом

instanceof
является оператор
is
. Он возвращает
true
, если тип времени выполнения заданного класса совместим с указанным типом. Версия C# приведенного выше кода будет иметь следующую форму:

string у = "a string";

object х = у;

if (х is System.String) {

 System.Console.WriteLine("x is a string");

}

Операторы равенства aрифметические, условные, побитовые, битового дополнения и сдвига

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

Преобразование типов

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