может 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рифметические, условные, побитовые, битового дополнения и сдвига
В обоих языках операторы равенства могут использоваться для тестирования чисел, символов, булевых примитивов, ссылочных переменных. Все другие операторы, упомянутые выше работают таким же образом.