Структура в windows forms c

Структуры. Общие понятия. Тип структуры. Структурная переменная. Модификаторы доступа к структурной переменной. Примеры использования структур в разных частях программы


Содержание

  • Вопрос/ответ
    • 1. Что такое структура в языке C#? Назначение структур
    • 2. Какая общая форма объявления структуры (структурного типа)? Ключевое слово struct
    • 3. Пример объявления структуры, которая описывает информацию о студенте
    • 4. Пример объявления, инициализации и использования структурной переменной
    • 5. Какой тип доступа по умолчанию имеют поля структурной переменной? Примеры
    • 6. В каких частях программного кода можно объявлять структуру и структурную переменную для Windows Forms приложений?
    • 7. Какое отличие между структурой и классом с точки зрения их представления в памяти?
    • 8. Какие есть отличия между структурами и классами?
    • 9. В каких случаях целесообразнее использовать структуры чем классы?
    • 10. Какие элементы языка программирования можно реализовывать в структуре?
    • 11. Можно ли создавать объект структуры с помощью оператора new?
    • 12. Поддерживают ли структуры наследование?
    • 13. Какой один базовый класс наследуют все структуры в C#?
    • 14. Могут ли поля (члены) структуры объявляться с ключевым словом protected?
    • 15. Могут ли поля (члены) структуры быть объявлены с ключевыми словами abstract и virtual?
  • Связанные темы

Поиск на других ресурсах:

1. Что такое структура в языке C#? Назначение структур

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

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

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

Использование структуры в программе происходит в 2 этапа:

  • объявление типа структуры;
  • объявление структурной переменной.

  ⇑

2. Какая общая форма объявления структуры (структурного типа)? Ключевое слово struct

Общая форма объявления типа структуры:

struct имя_типа_структуры : интерфейсы
{
    // объявление членов и методов структуры
    // ...
}

где

  • имя_типа_структуры – название структурного типа на основе которого будут объявляться объекты (переменные, экземпляры структуры);
  • интерфейсы – список интерфейсов, методы которых нужно реализовать в теле структуры.

  ⇑

3. Пример объявления структуры, которая описывает информацию о студенте

Пусть нужно сформировать базу данных студентов учебного заведения. Данные о студентах в базе данных можно представить структурами. В простейшем случае каждая структура должна объединять следующие данные:

  • фамилия студента;
  • имя студента;
  • год вступления в учебное заведение;
  • год рождения;
  • адрес проживания;
  • номер зачетной книжки;
  • текущий рейтинг студента.

Структура, которая описывает эту информацию будет иметь приблизительно такой вид:

struct Student
{
    public string name; // фамилия
    public string surname; // имя
    public int year; // год вступления в учебное заведение
    public int birth_year; // год рождения
    public string address; // адрес проживания
    public string book_number; // номер зачетной книжки
    public float rank; // рейтинг
}

  ⇑

4. Пример объявления, инициализации и использования структурной переменной

Пусть дано объявление структурной переменной, описывающей одну запись в телефонном справочнике:

struct Telephone
{
    public string number; // номер телефона
    public string name; // имя абонента
    public string surname; // фамилия абонента
    public string address; // адрес
    public int code; // почтовый код
}

Объявление и использование структурной переменной типа Telephone будет следующим:

// Объявление структурной переменной с именем T1 типа Telephone
Telephone T1;

// заполнение полей структурной переменной T1
T1.name = "Johnson";
T1.surname = "John";
T1.number = "77777777";
T1.code = 89300;
T1.address = "Boston";

  ⇑

5. Какой тип доступа по умолчанию имеют поля структурной переменной? Примеры

По умолчанию, поля структурной переменной имеют тип доступа private. Чтобы можно было иметь доступ к полям структурной переменной непосредственно, используется ключевое слово public.

Пример 1. Пусть дано объявление структуры, которая описывает информацию о студенте:

struct Student
{
    string name; // фамилия
    string surname; // имя
    int year; // год вступления в учебное заведение
    int birth_year; // год рождения
    string address; // адрес проживания
    string book_number; // номер зачетной книжки
    float rank; // рейтинг
}

В данной структуре все члены не имеют явным образом заданного модификатора доступа (private, public). По умолчанию, устанавливается модификатор доступа private. Это означает, что при объявлении переменной типа Student, невозможно будет доступиться к полям структуры непосредственно. То есть следующий программный код будет ошибочным:

Student St;
St.name = "Name of student"; // ошибка!
St.year = 1990; // ошибка!

Пример 2. Пусть дано объявление типа структуры, содержащей информацию о дате (число, месяц, год):

struct Date
{
    public int day; // число
    public int month; // месяц
    public int year; // год
}

Тогда, использование структуры в некотором методе может быть следующим:

// использование структурной переменной в коде некоторого метода
Date D; // объявление переменной с именем D типа "структура Date"

// заполнение полей структурной переменной
// поля объявлены как public
D.day = 14;
D.month = 1;
D.year = 1972;

  ⇑

6. В каких частях программного кода можно объявлять структуру и структурную переменную для Windows Forms приложений?

Для приложений, созданных по шаблону Windows Forms Application, тип структуры можно объявлять:

  • в пределах пространства имен но за пределами класса;
  • в пределах класса но за пределами методов класса.

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



  ⇑

7. Какое отличие между структурой и классом с точки зрения их представления в памяти?

Структуры относятся к значимым типам (value type). Это значит, что они неявно унаследованы от класса System.ValueType. К типам-значениям (структурным типам) относятся базовые (примитивные) типы данных, такие как short, int, uint, double, float, bool и другие, а также их псевдонимы System.Int32, System.Double, System.Single и другие.

Классы относятся к ссылочным типам (reference type).

С точки зрения размещения в памяти, между структурами и классами существует следующее отличие.

Если объявляется переменная (экземпляр) структурного типа, то этот экземпляр размещается в стеке полностью. Время жизни структуры определяется контекстом, в котором она определена. Как только переменная структурного типа выходит за пределы контекста, в котором она определена, то она сразу же удаляется из памяти.

Если объявляется переменная (ссылка) типа класса, то в стеке размещается только ссылка на экземпляр класса. Сам экземпляр размещается в области памяти, которая называется «куча» (heap). Чтобы создать экземпляр класса, обязательно нужно использовать оператор new. Удалением экземпляра класса из памяти занимается сборщик мусора (Garbage collector).

  ⇑

8. Какие есть отличия между структурами и классами?

При использовании структур и классов, можно выделить следующие основные отличия:

  • структуры принадлежат к типам значений, классы принадлежат к ссылочным типам;
  • при присваивании структур создается полная копия ее объекта, то есть выделяется память для дополнительной структуры. При присваивании классов ссылка на один класс присваивается ссылке на другой класс, и, как результат, обе ссылки указывают на один и тот же объект;
  • структуры не поддерживают наследование. Структура не может наследовать класс или другую структуру. Однако, структура может содержать переменную структурного типа;
  • в отличие от классов, в структурах нельзя объявлять (реализовывать) конструктор по умолчанию;
  • в отличие от классов, в структурах члены данных не могут быть объявлены с ключевым словом protected, поскольку структуры не поддерживают наследование;
  • в отличие от классов, структуры не поддерживают деструкторов;
  • структуры не могут объявляться с ключевыми словами abstract и virtual.

  ⇑

9. В каких случаях целесообразнее использовать структуры чем классы?

Хотя структуры владеют меньшим потенциалом чем классы, в некоторых случаях использование структур есть более эффективным. К таким случаям можно отнести случаи:

  • когда нужно сгруппировать небольшие объемы данных. В этом случае структуры используют для оптимизации продуктивности;
  • когда нужно повысить продуктивность. Структуры сохраняются в стеке, поэтому выделение/освобождение памяти происходит быстрее;
  • когда нужно сэкономить память под данные. Поскольку структуры принадлежат к типам-значениям, то при использовании структур используется меньший объем памяти. В случае с классами нужно использовать дополнительную ссылочную переменную.

Классы целесообразнее использовать в случаях:

  • когда функционала структур недостаточно для организации работы с данными;
  • когда нужно обрабатывать большие массивы информации.

  ⇑

10. Какие элементы языка программирования можно реализовывать в структуре?

В структуре можно реализовывать:

  • поля (члены данных структуры);
  • методы;
  • интерфейсы;
  • индексаторы;
  • свойства;
  • операторные методы;
  • события;
  • конструкторы (кроме конструктора по умолчанию).

  ⇑

11. Можно ли создавать объект структуры с помощью оператора new?

Можно. В этом случае после ключевого слова new вызывается конструктор по умолчанию.

Например. Использование оператора new для создания экземпляра структуры типа Date.

// Структура, которая описывает дату
struct Date
{
    public int day;
    public int month;
    public int year;
}

Демонстрация использования структуры типа Date:

// создание экземпляра структуры с помощью оператора new
Date D = new Date(); // вызывается конструктор по умолчанию

// заполнить поля структуры данными
D.day = 14;
D.month = 01;
D.year = 1972;

  ⇑

12. Поддерживают ли структуры наследование?

В отличие от классов, структуры наследование не поддерживают.

  ⇑

13. Какой один базовый класс наследуют все структуры в C#?

Все структуры неявно наследуют класс System.ValueType, который унаследован от System.Object.

  ⇑

14. Могут ли поля (члены) структуры объявляться с ключевым словом protected?

Не могут, поскольку структуры не поддерживают наследование.

  ⇑

15. Могут ли поля (члены) структуры быть объявлены с ключевыми словами abstract и virtual?

Не могут, поскольку структуры не поддерживают наследование.

  ⇑


Связанные темы

  • Структуры и методы. Инициализация структур. Конструкторы в структурах. Свойства в структурах
  • Использование массивов в структурах. Массивы структур. Вложенные структуры. Копирование структур
  • Перечисления
  • Интерфейсы. Использование интерфейсов в C#
  • Понятие класса. Описание класса. Объект класса. Конструктор класса Деструктор. Ключевое слово this

  ⇑


Содержание

  • Объявление структуры
  • Создание структуры
  • Конструкторы структур
  • Инициализатор структур struct
  • Копирование структур с изменением значений (оператор with)
  • Отличие структуры от класса в C#
    • Структура — тип значений, класс — ссылочный тип
    • Структуры не поддерживают наследование
    • Когда использовать структуры (struct), а когда классы (class) в C#
  • Итого

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

Структура (struct) в C# — это пользовательский тип данных, который используется наряду с классами и может содержать какие-либо данные и методы. Структурами также являются такие типы данных как  int, double и т.д. Основное отличие структуры (struct) от класса (class) заключается в том, что структура — это тип значений, а класс — это ссылочный тип.

Объявление структуры

Для того, чтобы объявить переменную типа структуры в C# используется ключевое слово struct:

struct имя_структуры
{
    // элементы структуры
}

После ключевого слова struct следует имя структуры и далее, в фигурных скобках — элементы структуры (поля, методы и т.д.). Например, определим структуру, которая описывает точку в трехмерном пространстве:

public struct Point3D
{ 
    public double X { get; set; }
    public double Y { get; set; }
    public double Z{ get; set; }

    public override string ToString()
    {
        return $"({X},{Y},{Z})";
    }
}

Наша структура содержит три свойства — координаты X,Y,Z и один переопределенный метод ToString, который возвращает строку с координатами точки. Обращение к полям, свойствам и методам структуры, как и в случае с классами, происходит с использованием имени переменной, например:

Point.X = 100;
Point.Y = 100;
Point.Z = 100;
Console.WriteLine(Point.ToString());

здесь Point — это имя переменной типа Point3D.

Создание структуры

Как и в случае с классами, структуры в C# можно создавать с использованием ключевого слова new:

Point3D Point = new Point3D();

После того, как структура создана, её полям и свойствам можно присваивать значения (см. в предыдущем пункте).

Начиная с .NET 5 в C# 9 можно использовать краткую форму записи new:

Point3D Point = new();

Если структура содержит только публичные поля (не путать со свойствами) и методы, то можно не вызывать конструктор, а сразу назначить значение полей и после этого вызывать методы структуру. Например:

   public struct Point3D
    {
        public double X;
        public double Y;
        public double Z;

        public override string ToString()
        {
            return $"({X},{Y},{Z})";

        }
    };
//не вызываем конструктор, а сразу задаем значение полей
    Point3D Point;
    Point.X = 100;
    Point.Y = 100;
    Point.Z = 100;
    Console.WriteLine(Point.ToString());

Начиная с версии C# 10 полям структуры можно присваивать значения по умолчанию, однако, в этом случае необходимо будет вызвать new(), чтобы создать экземпляр структуры. Например:

public struct Point3D
{
    public double X = 10;
    public double Y = 5;
    public double Z = 8;
    public override string ToString()
    {
        return $"({X},{Y},{Z})";
    }
}

Если мы попытаемся вывести в консоль значения полей вот так:

Point3D point;
Console.WriteLine(point.ToString());

то получим ошибку «Попытка доступа к неинициализированной переменной». Поэтому, необходимо получать доступ к переменной point с использованием оператора new:

Point3D point = new();
Console.WriteLine(point.ToString());

Конструкторы структур

Здесь, опять же, структуры ничем не отличаются от классов C#. У любой структуры есть как минимум один конструктор (конструктор по умолчанию) без параметров. При этом, мы можем создавать свои конструкторы и точно также, как и с классами вызывать их по цепочке, например:

public struct Point3D
{
    public double X = 10;
    public double Y = 5;
    public double Z = 8;
    public override string ToString()
    {
        return $"({X},{Y},{Z})";
    }

    public Point3D(double x) : this()
    {
        X = x;
        Y = 0;
        Z = 0;
    }

    public Point3D(double x, double y) : this(x)
    {
        Y = y;
        Z = 0;
    }

    public Point3D(double x, double y, double z) : this(x, y)
    {
        Z = z;
    }
}

Создаем структуры (struct)

Point3D point1 = new(10);
Point3D point2 = new(10, 20);
Point3D point3 = new(10, 30, 40);
Console.WriteLine(point1);
Console.WriteLine(point2);
Console.WriteLine(point3);

Вывод консоли

(10,0,0)
(10,20,0)
(10,30,40)

Начиная с версии C# 10 мы можем также создать для структуры свой конструктор без параметров:

//конструктор без параметров
public Point3D()
{
    X = 10;
    Y = 20;
    Z = 30;
}

Значения полей и свойств структуры, как в случае и с классами, можно задавать непосредственно при создании, используя следующую языковую конструкцию:

Point3D Point4 = new() { X = 24, Y = 45, Z = 22 };

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

Point3D Point4 = new(10, 20, 30) { X = 24, Y = 45, Z = 22 };
Console.WriteLine(Point4);

то значения полей будут теми, которые мы указываем в инициализаторе, т.е. 24, 45 и 22.

Копирование структур с изменением значений (оператор with)

Начиная с версии C# 10 мы можем копировать значения структур с изменениями, например:

Point3D Point4 = new() { X = 24, Y = 45, Z = 22 };
Point3D Point5 = Point4 with { X = 100 };//меняем значение X
Console.WriteLine(Point4);
Console.WriteLine(Point5);

Вывод в консоли:

Отличие структуры от класса в C#

Думаю, что после прочтения всего, что было выше, у любого начинающего программировать в C# человека возникнет резонный вопрос: если у структур в C# всё тоже самое, что и у классов. то зачем нам эти структуры нужны и, если всё-таки они нужны, то когда их использовать? Попробуем в кратце разобраться с этим вопросом вместе.

Структура — тип значений, класс — ссылочный тип

Если не вдаваться далеко в подробности работы программ, то основное отличие struct от class заключается в том, что структура храниться целиком в стеке, а объект класса храниться в куче, а ссылка на него — в стеке. В результате этого, доступ к данным структуре будет путь не намного, но быстрее, чем к классу. О том, что такое стек и куча мы ещё поговорим позднее.

Структуры не поддерживают наследование

В отличие от классов C#, наследование структур не поддерживается, то есть вот такой код приведет к ошибке:

struct Point3DType2 : Point3D
{ }

Когда использовать структуры (struct), а когда классы (class) в C#

Конечно, вопрос о том, что лучше использовать зависит, в первую очередь, от того в контексте чего задается такой вопрос, но основная рекомендация от Microsoft может быть сформулирована следующим образом: структуры (struct) стоит использовать в том случае, если ваш объект содержит минимальное количество каких-либо логически связанных операций или не содержит их вообще.

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

Если же мы пробуем описать с помощью своего типа данных, например, автомобиль, то тут уже логика может быть самая разветвленная: проверка наличия топлива в баке, технические характеристики, оценка состояния в зависимости от каких-либо внешних или внутренних факторов и т.д.  Соответственно, в этом случае, более предпочтительным будет использование не структуры, а класса.

Итого

Как и классы в C#, структуры позволяют определить пользовательский тип данных в вашем проекте. При этом, на первый взгляд, структуры (struct) практически ни чем не отличаются от классов, однако различия есть: во-первых, структуры относятся к типам значений, во-вторых, структуры не поддерживают механизмов наследования. Использовать или не использовать структуры — решение самого разработчика, однако, рекомендуется использовать тип struct только в том случае, если ваш пользовательский тип данных содержит минимум бизнес-логики или не содержит её вовсе.

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

Структуры

Последнее обновление: 12.02.2023

Наряду с классами структуры представляют еще один способ создания собственных типов данных в C#. Более того многие примитивные типы, например,
int, double и т.д., по сути являются структурами.

Определение структуры

Для определения структуры применяется ключевое слово struct:

struct имя_структуры
{
	// элементы структуры
}

После слова struct идет название структуры и далее в фигурных скобках размещаются элементы структуры — поля, методы и т.д.

Например, определим структуру, которая будет называться Person и которая будет представлять человека:

struct Person
{
}

Как и классы, структуры могут хранить состояние в виде полей (переменных) и определять поведение в виде методов. Например, добавим в структуру Person пару полей и метод:

struct Person
{
    public string name;
    public int age;

    public void Print()
    {
        Console.WriteLine($"Имя: {name}  Возраст: {age}");
    }
}

В данном случае определены две переменные — name и age для хранения соответственно имени и возраста человека и метод Print для вывода информации о человеке на консоль.

И как и в случае с классами, для обращения к функциональности структуры — полям, методам и другим компонентам структуры
применяется точечная нотация — после объекта структуры ставится точка, а затем указывается компонент структуры:

объект.поле_структуры
объект.метод_структуры(параметры_метода)

Создание объекта структуры

Инициализация с помощью конструктора

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

new название_структуры();

Например, создадим объект структуры Person с помощью конструктора по умолчанию:

Person tom = new Person();	// вызов конструктора
// или так 
// Person tom = new();

tom.name = "Tom";	// изменяем значение по умолчанию в поле name

tom.Print();    // Имя: Tom  Возраст: 0

struct Person
{
    public string name;
    public int age;

    public void Print()
    {
        Console.WriteLine($"Имя: {name}  Возраст: {age}");
    }
}

В данном случае создается объект tom. Для его создания вызывается конструктор по умолчанию, который устанавливает значения по умолчанию для его полей. Для числовых данных это значение 0, поэтому
поле age будет иметь значение 0. Для строк это значение null, которое указывает на отсутствие значения. Но далее, если поля доступны
(а в данном случае поскольку они имеют модификатор public они доступны), мы можем изменить их значения. Так, здесь полю name присваивается строка «Tom». Соответственно
при выполнении метода Print() мы получим следующий консольный вывод:

Непосредственная иницилизация полей

Если все поля структуры доступны (как в случае с полями структуры Person, который имеют модификатор public),
то структуру можно инициализировать без вызова конструктора. В этом случае необходимо присвоить значения всем полям структуры перед получением значений полей и обращением к методам структуры.
Например:

Person tom;			// не вызываем конструктор
// инициализация полей
tom.name = "Sam";
tom.age = 37;

tom.Print();    // Имя: Sam  Возраст: 37

struct Person
{
    public string name;
    public int age;

    public void Print()
    {
        Console.WriteLine($"Имя: {name}  Возраст: {age}");
    }
}

Инициализация полей по умолчанию

Стоит отметить, что начиная с версии C# 10, мы можем напрямую инициализировать поля структуры при их определении (до C# 10 это делать было нельзя):

Person tom = new Person();
tom.Print();    // Имя:Tom  Возраст: 1

struct Person
{
	// инициализация полей значениями по умолчанию - доступна с C#10
    public string name = "Tom";
    public int age = 1;
    public Person() { }
    public void Print() =>Console.WriteLine($"Имя: {name}  Возраст: {age}");
}

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

Конструкторы структуры

Как и класс, структура может определять конструкторы. Например, добавим в структуру Person конструктор:

Person tom = new();
Person bob = new("Bob");
Person sam = new("Sam", 25);

tom.Print();    // !!!! Имя:   Возраст: 0
bob.Print();    // Имя: Bob  Возраст: 1 
sam.Print();    // Имя: Sam  Возраст: 25

struct Person
{
    public string name;
    public int age;

    public Person(string name = "Tom", int age = 1)
    {
        this.name = name;
        this.age = age;
    }
    public void Print() => Console.WriteLine($"Имя: {name}  Возраст: {age}");
}

В данном случае в структуре Person определен конструктор с двумя параметрами, для которых предоставлены значения по умолчания. Однако обратите внимание на
создание первого объекта структуры:

Person tom = new();	// по прежнему используется конструктор без параметров по умолчанию
tom.Print();    // !!!! Имя:   Возраст: 0

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

Однако начиная с версии C# 10 мы можем определить свой конструктор без параметров:

Person tom = new();

tom.Print();    // Имя: Tom  Возраст: 37

struct Person
{
    public string name;
    public int age;

    public Person()
    {
        name = "Tom";
        age = 37;
    }
    public void Print() => Console.WriteLine($"Имя: {name}  Возраст: {age}");
}

Стоит отметить, что до версии C# 11 при определении конструктора структуру в нем необходимо было инициализировать все поля структуры, начиная с версии C# 11 это делать необязательно.

В случае если нам необходимо вызывать конструкторы с различным количеством параметров, то мы можем, как и в случае с классами, вызывать их по цепочке:

Person tom = new();
Person bob = new("Bob");
Person sam = new("Sam", 25);

tom.Print();    // Имя: Tom  Возраст: 1
bob.Print();    // Имя: Bob  Возраст: 1 
sam.Print();    // Имя: Sam  Возраст: 25

struct Person
{
    public string name;
    public int age;

    public Person() : this("Tom")
    { }
    public Person(string name) : this(name, 1)
    { }
    public Person(string name, int age)
    {
        this.name = name;
        this.age = age;
    }
    public void Print() => Console.WriteLine($"Имя: {name}  Возраст: {age}");
}

Консольный вывод программы:

Имя: Tom  Возраст: 1
Имя: Bob  Возраст: 1 
Имя: Sam  Возраст: 25

Инициализатор структуры

Также, как и для класса, можно использовать инициализатор для создания структуры:

Person tom = new Person { name = "Tom", age = 22 };

tom.Print();    // Имя: Tom  Возраст: 22

struct Person
{
    public string name;
    public int age;
    public void Print() => Console.WriteLine($"Имя: {name}  Возраст: {age}");
}

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

Копирование структуры с помощью with

Если нам необходимо скопировать в один объект структуры значения из другого с небольшими изменениями, то мы можем использовать оператор
with:

Person tom = new Person { name = "Tom", age = 22 };
Person bob = tom with { name = "Bob" };
bob.Print();    // Имя: Bob  Возраст: 22

В данном случае объект bob получает все значения объекта tom, а затем после оператора with в фигурных скобках указывается
поля со значениями, которые мы хотим изменить.

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

В исходном коде класса System.Windows.Forms.Control, можно посмотреть реализацию свойства Size, как пример того, как Microsoft использует структуры.

У контрола есть поля width и height. Одноименные свойства Width и Height и свойство Size, которое возвращает значения width и height в виде одной структуры типа System.Drawing.Size. Для изменений размеров у вас есть целых два пути: задать ширину и высоту отдельно через соответствующие свойства, либо установить оба размера сразу с помощью структуры Size, например скопированной из другого контрола.

Если рассмотреть свойство Location, то найти отдельные свойства для X и Y не получится, их просто нет, хотя внутри используются отдельные поля x и y для хранения координат. В принципе, можно было и внутри использовать структуру, т.к. координаты точки довольно редко используются по-отдельности.

На мой взгляд — это достаточно неплохой пример практического применения структур с учетом их особенностей.

У Microsoft есть и менее удачные примеры, например свойство Control.Font, в котором кажется довольно странным, не иметь возможности указать, например атрибут шрифта Bold без замены всей структуры Font, но если внимательно присмотреться к исходникам можно заметить, что это свойство связано с неуправляемым кодом WinAPI и скорее всего особого выбора не было, не считая конечно нереального на практике варианта «быстренько запилить новый API».

Применяйте имеющиеся инструменты по назначению (в разных языках оно может быть разным, это нормально).

Вы уже знаете, что классы относятся к ссылочным типам данных. Это означает, что объекты конкретного класса доступны по ссылке. Ссылка -это 32/64-х битный адрес, указывающий на расположение членов-данных  в управляемой куче, в отличие от значений простых типов, доступных непосредственно.

Но иногда прямой доступ к объектам (например, как к значениям простых типов) полезно иметь ради повышения эффективности программы. Ведь каждый доступ к объектам по ссылке связан с дополнительными издержками на расход вычислительных ресурсов и оперативной памяти.

Для разрешения подобных затруднений в C# предусмотрена структура, которая подобна классу, но относится к типу значений, а не к ссылочному типу данных.

Структуры отличаются от классов тем, как они сохраняются в памяти и как к ним осуществляется доступ (для начала – краткая формула «классы — это ссылочные типы, размещаемые в куче, структуры — типы значений, размещаемые в стеке»). Эта формула не совсем точная, пояснения см. позже. Структуры отличаются от классов некоторыми свойствами (например, структуры не поддерживают наследование).

Из соображений производительности следует использовать структуры для небольших типов данных. Однако в отношении синтаксиса структуры очень похожи на классы.

Первое и очевидное отличие состоит в том, что при их объявлении используется ключевое слово struct вместо class. Ниже приведена общая форма объявления структуры:

struct имя
{
объявления членов
}
где имя обозначает конкретное имя структуры.

Как у класса, так и у каждой структуры имеются свои члены: методы, поля, индексаторы, свойства, операторные методы и события. Так в структуре Double (библиотека System) определено 6 констант, 6 операторов отношения, 19 методов, 5 интерфейсов (проверьте, используя интеллектуальную подсказку). Не многовато ли для вещественного числа, как вы думаете?

В структурах допускается также определять конструкторы. В то же время для структуры нельзя определить конструктор, используемый по умолчанию (без параметров), который определяется для всех структур автоматически и не подлежит изменению. Такой конструктор инициализирует поля структуры значениями, задаваемыми по умолчанию (false для типа bool, 0 – для чисел). А поскольку структуры в отличие от классов не поддерживают наследование, то их члены нельзя указывать как abstract, virtual  или  protected.

Экземпляр (можно говорить и «объект») структуры может быть создан с помощью оператора new таким же образом, как и объект класса, но в этом нет особой необходимости. Когда используется оператор new, то вызывается конструктор, используемый по умолчанию. А когда этот оператор не используется, объект по-прежнему создается, хотя и не инициализируется. В этом случае инициализацию любых членов структуры придется выполнить вручную. Рассмотрим пример.

// Пример: Структуры
using System;
namespace ConsoleApplication1
{
  // Создадим структуру вне класса Program
  struct student
  {
     public string name;    // поле - имя
     public byte age;       // поле - возраст
     public student(string Name, byte Age)  // конструктор
     {
        this.name = Name;
        age = Age;   // указатель this можно не добавлять
     }
     public void WriteUserInfo()   // метод для вывода
     {
        Console.WriteLine("Имя: {0}, возраст: {1}", name, age);
     } 
  }        // конец объявления структуры
  class Program
  {
     static void Main()
     {
        student stud1;    // Без конструктора
        stud1.name = "Петр";
        stud1.age = 18;
        Console.Write("студент1: ");
        stud1.WriteUserInfo();
        student stud2 = new student("Елена", 17);  // с конструктором
        Console.Write("студент2: ");
        stud2.WriteUserInfo();
 // Отличие структур от классов – в передаче по значению
        stud1 = stud2;   // пересылка
        stud2.name = "Наталья";  // изменение полей структуры
        stud2.age = 19;
        Console.Write("\nстудент1: ");
        stud1.WriteUserInfo();
        Console.Write("студент2: ");
        stud2.WriteUserInfo();
        Console.ReadKey();
     }
  }
}

Результат выполнения программы:

34
Исследуем программу. Закомментируем вторую строку в методе Main():
// stud1.name = «Петр»;
При запуске программы получим сообщение об ошибке:
Использование локальной переменной «stud1», которой не присвоено значение.
Хотя структура stud1 объявлена, но полю name никакого значения не присвоено, что приводит к ошибке. Такая же ошибка возникнет, если мы станем использовать переменную целого типа, которая объявлена, но не инициализирована.
Такой вот жесткий контроль компилятора за нашими действиями!

Проверим, как работает конструктор без параметров. Первую строку метода Main() заменим на
student stud1 = new student();  
Вторую и третью строку – закомментируем. Тогда при выводе результата в 1 строке получим:
студент 1: Имя: , возраст: 0
Следовательно, полю name была присвоена пустая строка, а полю возраст – число 0.

Проверим, как работает защита данных. В второй строке описания структуры student удалим модификатор поля public, т.е. получим byte age;
При запуске программы получим два сообщения об ошибке:
«ConsoleApplication1.student.age» недоступен из-за его уровня защиты
в операторах stud1.age = 18; и  stud2.age = 19;

Это означает, что так как по умолчанию поле age является полем private, то оно не может быть изменено в другом классе с помощью оператора присваивания, однако оно доступно методам класса student, объявленным как public. С учетом этих результатов, программа может быть записана так:

using System;
namespace ConsoleApplication1
{
   struct student
   {
      string name;
      byte age;
      public student(string Name, byte Age)
      {
         name = Name;
         age = Age;
      }
      public void WriteUserInfo()
      {
         Console.WriteLine("Имя: {0}, возраст: {1}", name, age);
      }
   }
   class Program
   {
      static void Main()
      {
         student stud1 = new student("Петр",18);
         stud1.WriteUserInfo();
         student stud2 = new student("Елена", 17);
         stud2.WriteUserInfo();
         Console.ReadKey();
      }
   }
}

Здесь поля объектов stud1 и stud2 структуры student являются private-полями, а метод и конструктор объявлены как public.

А теперь ВНИМАНИЕ! Ключевая идея — Создание сложных конструкций данных, используя один тип данных, как элемент другой конструкции. В статье про типы данных мы выяснили, что все встроенные типы, относящиеся к типам значений (их еще называют простыми типами данных), являются структурами, хотя фактически каждая из них имеет одно поле, содержащее значение числа, символа или булевой переменной.

Структура позволяет объединять несколько различных по типу элементов под одним именем. Более того можно использовать неоднократное вложение одних типов данных в другие, используя структуры.

Для понимания этой идеи рассмотрим пример. Прототипом для него являются структуры из библиотеки System. Drawing:  Point, Size и Rectangle.

Известно, что точка на экране задается парой целых чисел (X,Y) в пикселях. Объединим эти два числа в структуру точка. Установим максимальную защиту (private – по умолчанию) для этих полей. Добавим конструктор с параметрами точка(x,y) для инициализации объектов структуры точка, а также метод Get() для извлечения полей в строковом формате.

Размер прямоугольника на экране также задается парой чисел: шириной и высотой. Соответственно объявим структуру размер с полями (W,H). Добавим аналогичный конструктор с параметрами размер(w,h) для инициализации объектов структуры размер, а также метод Get() для извлечения полей в строковом формате.

Прямоугольник на экране определяется координатами верхнего левого угла (точка) и размером изображения (размер). Поэтому третью структуру построим на основе первых двух, назовем ее Rect (сокращенно от «прямоугольник»), полями которой будут объекты первых двух структур: точка P и размер S. Эти поля также будут защищенными (private – по умолчанию). Добавим в эту структуру конструктор с параметрами public Rect(int x, int y, int w, int h) и три метода: Get() для извлечения информации о прямоугольнике, Get_P() и Get_S для извлечения координат и размеров по отдельности.

В методе Main( ) последовательно инициализируем объект Rect r и покажем работу методов всех этих трех структур.

using System;
namespace прямоугольник
{
   struct точка
   {
      int X;
      int Y;
      public точка (int x, int y)
      {
         X = x;
         Y = y;
      }
      public string Get()
      {
         return X.ToString()+","+Y.ToString();
      }
   }
   struct размер
   {
      int W;
      int H;
      public размер(int w, int h)
      {
         W = w;
         H = h;
      }
      public string Get()
      {
         return W.ToString() + "x" + H.ToString();
      }
   }
   struct Rect
   {
      точка P;
      размер S;
      public Rect(int x, int y, int w, int h)
      {
         P = new точка(x,y);
         S = new размер(w,h);
      }
      public void Get()
      {
         Console.Write("Параметры прямоугольника:  ");
         Console.Write("Координаты: ({0})", P.Get());
         Console.Write("   Размеры - {0}", S.Get());
         Console.WriteLine();
      }
      public точка Get_P()
      {
         return P;
      }
      public размер Get_S()
      {
         return S;
      }
   }
   class Program
   {
      static void Main(string[] args)
      {
         Rect r = new Rect(100,50,30,40);
         r.Get();
         точка q = r.Get_P();    // т.к. r.P; - ошибка
         string z = "Координаты: (" + q.Get()+")";
         Console.WriteLine(z);
         размер d = r.Get_S();   // т.к. r.S; - ошибка
         z = "Размеры: " + d.Get();
         Console.WriteLine(z);
         Console.ReadKey();
      }
   }
}

Результат:

35
Конечно, если бы поля всех структур были объявлены с модификатором public, то в принципе можно обходиться структурами, имеющими только поля без методов. Но помня о том, что структуры похожи на классы, следует и к ним применять те же общие принципы, что и для классов в части защиты данных.

Далее рассмотрим отличия структур от классов.


NEW: Наш Чат, в котором вы можете обсудить любые вопросы, идеи, поделиться опытом или связаться с администраторами.


Помощь проекту:

  • Счетчик fps для игр windows 11
  • Структура gpt диска windows 10
  • Странный шрифт в windows 10
  • Сферум приложение скачать для windows
  • Существует ли windows 10 32 bit