Как работает auto-property?
public List PointList < get; set; >— это тоже самое, что и в вашем случае:
List _points; public List < Vector2 >PointList < get < return _points; >set < _points = value; >>
Вот решарпер и предлагает упростить код. Убирается лишняя переменная _points , читается проще. На одном свойстве это может и не заметно, но если в классе куча таких полей, то у вас, по сути, было бы куча лишних переменных и куча похожих названий.
Если посмотреть, во что компилятор сгенерирует auto-property, то тоже самое будет. К примеру из:
public int IntProperty
При генерации получится что-то вроде:
private int \u003CIntProperty\u003Ek__BackingField; public int IntProperty < get < return this.\u003CIntProperty\u003Ek__BackingField; >private set < this.\u003CIntProperty\u003Ek__BackingField = value; >>
Описание структуры данных
Для работы с базой данных в PHP мы будем использовать Doctrine — набор библиотек для управления базами данных: Doctrine DBAL (слой абстракции базы данных), Doctrine ORM (библиотека для манипулирования содержимым нашей базы данных с помощью объектов PHP) и Doctrine Migrations.
Настройка Doctrine ORM
Как узнать, подключена ли Doctrine к базе данных? В рецепт Doctrine добавлен конфигурационный файл config/packages/doctrine.yaml , в котором находятся параметры подключения. Основным параметром в этом файле является DSN-строка (Data Source Name — «имя источника данных»), содержащая всю информацию о подключении: учётные данные, хост, порт и т.д. По умолчанию Doctrine ищет переменную среды DATABASE_URL .
Конфигурация почти всех установленных пакетов находится в директории config/packages/ . Как правило, настройки по умолчанию подходят для большинства приложений.
Разбираемся в соглашениях по именованию переменных окружения в Symfony
Можно инициализировать переменную DATABASE_URL в файлах .env или .env.local . Благодаря рецепту пакета, пример значения переменной DATABASE_URL уже присутствует в файле .env . Это громоздкое решение, поскольку локальный порт PostgreSQL, открытый через Docker, может измениться. Есть вариант и получше.
Вместо записи переменной DATABASE_URL в файле, мы можем добавить ко всем командам префикс symfony и переменная окружения установится автоматически во всех сервисах, запущенных в Docker и/или Platform.sh (при открытом туннеле).
Docker Compose и Platform.sh отлично работают с Symfony благодаря переменным окружения.
Проверьте все установленные переменные окружения командой symfony var:export :
$ symfony var:export
DATABASE_URL=postgres://app:!ChangeMe!@127.0.0.1:32781/app?sslmode=disable&charset=utf8 # .
Помните имя сервиса database , используемое в конфигурациях Docker и Platform.sh? Имена сервисов используются в качестве префиксов для определения переменных окружения, таких как DATABASE_URL . Если ваши сервисы названы в соответствии с соглашениями Symfony, никакой другой конфигурации не требуется.
Базы данных — это не единственный сервис, который использует соглашения Symfony. Например, то же самое можно сказать и о Mailer (через переменную окружения MAILER_DSN ).
Изменение начального значения DATABASE_URL в файле .env
Всё же изменим переменную окружения DATABASE_URL в файле .env , и укажем, что подключением по умолчанию должен быть PostgreSQL:
1 2 3 4 5 6 7 8 9 10 11
--- a/.env +++ b/.env @@ -29,7 +29,7 @@ MESSENGER_TRANSPORT_DSN=doctrine://default?auto_setup=0 # # DATABASE_URL="sqlite:///%kernel.project_dir%/var/data.db" # DATABASE_URL="mysql://app:!ChangeMe!@127.0.0.1:3306/app?serverVersion=8&charset=utf8mb4" -DATABASE_URL="postgresql://app:!ChangeMe!@127.0.0.1:5432/app?serverVersion=14&charset=utf8" +DATABASE_URL="postgresql://127.0.0.1:5432/db?serverVersion=14&charset=utf8" ### < doctrine/doctrine-bundle ### ###>symfony/messenger ###
Почему эту информацию необходимо дублировать в двух разных местах? Потому что в момент сборки на некоторых облачных платформах URL-адрес базы данных может быть ещё неизвестен, но Doctrine необходимо знать драйвер базы данных, чтобы создать собственную конфигурацию. Таким образом, хост, имя пользователя и пароль не имеют значения.
Создание классов сущностей
Класс, описывающий объект конференции со следующими свойствами:
- city — город, в котором проводится конференция;
- year — год проведения конференции;
- international — флаг, указывающий, является ли конференция местной или международной (SymfonyLive или SymfonyCon).
Бандл Maker может помочь нам создать класс (класс Entity), представляющий конференцию.
Пришло время создать сущность Conference :
$ symfony console make:entity Conference
Эта команда является интерактивной: она проведёт вас через процесс добавления всех необходимых полей. Используйте следующие ответы (большинство из них являются ответами по умолчанию, так что вы можете нажать клавишу «Enter», чтобы их использовать):
- city , string , 255 , no ;
- year , string , 4 , no ;
- isInternational , boolean , no .
Полный результат выполнения команды указан ниже:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
created: src/Entity/Conference.php created: src/Repository/ConferenceRepository.php Entity generated! Now let's add some fields! You can always add more fields later manually or by re-running this command. New property name (press to stop adding fields): > city Field type (enter ? to see all types) [string]: > Field length [255]: > Can this field be null in the database (nullable) (yes/no) [no]: > updated: src/Entity/Conference.php Add another property? Enter the property name (or press to stop adding fields): > year Field type (enter ? to see all types) [string]: > Field length [255]: > 4 Can this field be null in the database (nullable) (yes/no) [no]: > updated: src/Entity/Conference.php Add another property? Enter the property name (or press to stop adding fields): > isInternational Field type (enter ? to see all types) [boolean]: > Can this field be null in the database (nullable) (yes/no) [no]: > updated: src/Entity/Conference.php Add another property? Enter the property name (or press to stop adding fields): > Success! Next: When you're ready, create a migration with make:migration
Класс Conference находится в пространстве имён App\Entity\ .
Также команда сгенерировала класс репозитория для работы с Doctrine: App\Repository\ConferenceRepository .
Сгенерированный код выглядит следующим образом (представлена только небольшая часть файла):
src/Entity/Conference.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
namespace App\Entity; use App\Repository\ConferenceRepository; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity(repositoryClass: ConferenceRepository::class)] class Conference < #[ORM\Column(type: 'integer')] #[ORM\Id, ORM\GeneratedValue()] private $id; #[ORM\Column(type: 'string', length: 255)] private $city; // . public function getCity(): ?string < return $this->city; > public function setCity(string $city): self < $this->city = $city; return $this; > // . >
Обратите внимание, что это обычный PHP-класс без элементов Doctrine. Атрибуты используются для добавления метаданных, позволяющих Doctrine связать класс сущности с соответствующей таблицей в базе данных.
Doctrine добавила свойство id для хранения первичного ключа строки в таблице базы данных. Этот ключ ( ORM\Id() ) создаётся автоматически ( ORM\GeneratedValue() ) с помощью стратегии, которая зависит от движка базы данных.
Теперь сгенерируйте класс сущности для комментариев к конференции:
$ symfony console make:entity Comment
Введите следующие ответы:
- author , string , 255 , no ;
- text , text , no ;
- email , string , 255 , no ;
- createdAt , datetime_immutable , no .
Связывание сущностей
Обе сущности, конференция и комментарий, должны быть взаимосвязаны. Конференция может иметь ноль или более комментариев, это называется связью один-ко-многим.
Используйте команду make:entity ещё раз, чтобы добавить эту связь в класс Conference :
$ symfony console make:entity Conference
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
Your entity already exists! So let's add some new fields! New property name (press to stop adding fields): > comments Field type (enter ? to see all types) [string]: > OneToMany What class should this entity be related to?: > Comment A new property will also be added to the Comment class. New field name inside Comment [conference]: > Is the Comment.conference property allowed to be null (nullable)? (yes/no) [yes]: > no Do you want to activate orphanRemoval on your relationship? A Comment is "orphaned" when it is removed from its related Conference. e.g. $conference->removeComment($comment) NOTE: If a Comment may *change* from one Conference to another, answer "no". Do you want to automatically delete orphaned App\Entity\Comment objects (orphanRemoval)? (yes/no) [no]: > yes updated: src/Entity/Conference.php updated: src/Entity/Comment.php
Если в качестве ответа на вопрос о типе данных вы введёте ? , то вы получите список всех поддерживаемых типов:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
Main types * string * text * boolean * integer (or smallint, bigint) * float Relationships / Associations * relation (a wizard will help you build the relation) * ManyToOne * OneToMany * ManyToMany * OneToOne Array/Object Types * array (or simple_array) * json * object * binary * blob Date/Time Types * datetime (or datetime_immutable) * datetimetz (or datetimetz_immutable) * date (or date_immutable) * time (or time_immutable) * dateinterval Other Types * decimal * guid * json_array
Взгляните на список изменений в классах сущностей после добавления этой связи:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
--- a/src/Entity/Comment.php +++ b/src/Entity/Comment.php @@ -36,6 +36,12 @@ class Comment */ private $createdAt; + #[ORM\ManyToOne(inversedBy: 'comments')] + #[ORM\JoinColumn(nullable: false)] + private Conference $conference; + public function getId(): ?int < return $this->id; @@ -88,4 +94,16 @@ class Comment return $this; > + + public function getConference(): ?Conference + + return $this->conference; + > + + public function setConference(?Conference $conference): self + + $this->conference = $conference; + + return $this; + > > --- a/src/Entity/Conference.php +++ b/src/Entity/Conference.php @@ -2,6 +2,8 @@ namespace App\Entity; +use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\Common\Collections\Collection; use Doctrine\ORM\Mapping as ORM; /** @@ -31,6 +33,16 @@ class Conference */ private $isInternational; + #[ORM\OneToMany(targetEntity: Comment::class, mappedBy: "conference", orphanRemoval: true)] + private $comments; + + public function __construct() + + $this->comments = new ArrayCollection(); + > + public function getId(): ?int < return $this->id; @@ -71,4 +83,35 @@ class Conference return $this; > + + /** + * @return Collection + */ + public function getComments(): Collection + + return $this->comments; + > + + public function addComment(Comment $comment): self + + if (!$this->comments->contains($comment)) + $this->comments[] = $comment; + $comment->setConference($this); + > + + return $this; + > + + public function removeComment(Comment $comment): self + + if ($this->comments->contains($comment)) + $this->comments->removeElement($comment); + // set the owning side to null (unless already changed) + if ($comment->getConference() === $this) + $comment->setConference(null); + > + > + + return $this; + > >
Всё, что вам нужно для управления связями, было сгенерировано автоматически. Теперь это ваш код, поэтому не стесняйтесь его изменять, как вам нравится.
Добавление дополнительных свойств
Я только что понял, что мы забыли добавить одно свойство к сущности комментария: участники, возможно, захотят приложить фотографию с конференции, чтобы наглядно проиллюстрировать про свои отзывы.
Выполните команду make:entity ещё раз и добавьте свойство/столбец photoFilename типа string с возможностью иметь значение null , так как загрузка фотографии не обязательна:
$ symfony console make:entity Comment
Миграция базы данных
Модель проекта теперь полностью описана двумя сгенерированными классами.
Далее нам нужно создать таблицы базы данных, связанные с этими сущностями.
Doctrine Migrations идеально подходит для такой задачи. Этот пакет был установлен ранее в виде зависимости для пакета orm .
Миграция — это класс, описывающий изменения, необходимые для обновления схемы базы данных с текущего состояния на новое, определённой в атрибутах сущности. Поскольку на данный момент база данных пуста, миграция должна состоять из создания двух таблиц.
Давайте посмотрим, что сгенерировала Doctrine:
$ symfony console make:migration
Обратите внимание на сгенерированное имя файла в выводе командной строки (имя, которое выглядит как migrations/Version20191019083640.php ):
migrations/Version20191019083640.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
namespace DoctrineMigrations; use Doctrine\DBAL\Schema\Schema; use Doctrine\Migrations\AbstractMigration; final class Version00000000000000 extends AbstractMigration < public function up(Schema $schema): void < // this up() migration is auto-generated, please modify it to your needs $this->addSql('CREATE SEQUENCE comment_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); $this->addSql('CREATE SEQUENCE conference_id_seq INCREMENT BY 1 MINVALUE 1 START 1'); $this->addSql('CREATE TABLE comment (id INT NOT NULL, conference_id INT NOT NULL, author VARCHAR(255) NOT NULL, text TEXT NOT NULL, email VARCHAR(255) NOT NULL, created_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, photo_filename VARCHAR(255) DEFAULT NULL, PRIMARY KEY(id))'); $this->addSql('CREATE INDEX IDX_9474526C604B8382 ON comment (conference_id)'); $this->addSql('CREATE TABLE conference (id INT NOT NULL, city VARCHAR(255) NOT NULL, year VARCHAR(4) NOT NULL, is_international BOOLEAN NOT NULL, PRIMARY KEY(id))'); $this->addSql('ALTER TABLE comment ADD CONSTRAINT FK_9474526C604B8382 FOREIGN KEY (conference_id) REFERENCES conference (id) NOT DEFERRABLE INITIALLY IMMEDIATE'); > public function down(Schema $schema): void < // . > >
Обновление локальной базы данных
Теперь вы можете запустить сгенерированную ранее миграцию для обновления схемы локальной базы данных:
$ symfony console doctrine:migrations:migrate
Схема локальной базы данных теперь актуальна и подготовлена для хранения данных.
Обновление базы данных в продакшене
Шаги, необходимые для миграции базы данных на продакшене, такие же, с которыми вы уже знакомы: фиксация изменений и развёртывание.
При развёртывании проекта, Platform.sh не только обновляет код, но и выполняет миграцию базы данных, если таковая имеется (это выясняется при помощи команды doctrine:migrations:migrate ).
- Базы данных и Doctrine ORM в приложениях Symfony;
- Видеокурс по Doctrine на SymfonyCasts;
- Работа с ассоциациями/связями в Doctrine;
- Документация DoctrineMigrationsBundle.
Autogenerated properties что это
Данное руководство устарело. Актуальное руководство: Руководство по Entity Framework Core 7
Последнее обновление: 15.11.2020
Если при добавлении или обновлении нового объекта у него уже установлено значение для свойства, Entity Framework использует это значение при вставке или обновлении в таблицу. Если для свойства явным образом не установлено значение, то для свойства устанавливается значение по умолчанию ( null для string , 0 для int , Guid.Empty для Guid и т.д.).
В зависимости от используемого провайдера базы данных, значения для свойств могут генерироваться на стороне клиента с помощью EF, либо же генерироваться уже на стороне базы данных при добавлении. Если значение генерируется базой данных, тогда при добавлении объекта в контекст EF может назначить временное значение. Это временное значение будет заменено значением, сгенерированным базой данных при вызове метода SaveChanges() .
Генерация ключей
По умолчанию для свойств первичных ключей, которые представляют типы int или GUID и которые имеют значение по умолчанию, генерируется значение при вставке в базу данных. Для всех остальных свойств значения по умолчанию не генерируется.
Например, пусть у нас имеет следующая модель:
public class User < public int Id < get; set; >public string Name < get; set; >> public class ApplicationContext : DbContext < public DbSetUsers < get; set; >public ApplicationContext() < Database.EnsureDeleted(); Database.EnsureCreated(); >protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) < optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=helloappdb;Trusted_Connection=True;"); >>
То после добавления в базу данных мы сможем получить сгенерированный Id:
using (ApplicationContext db = new ApplicationContext()) < User user = new User < Name = "Tom" >; Console.WriteLine($"Id перед добавлением в контекст "); // db.Users.Add(user); db.SaveChanges(); Console.WriteLine($"Id после добавления в базу данных "); // DatabaseGeneratedAttribute
Атрибут DatabaseGeneratedAttribute преставляет аннотацию, которая позволяет изменить поведение базы данных при добавлении или изменении.
Например, мы хотим отключить автогенерацию значения при добавлении:
using System.ComponentModel.DataAnnotations.Schema; public class User < [DatabaseGenerated(DatabaseGeneratedOption.None)] public int Id < get; set; >public string Name < get; set; >>
И если теперь мы попробуем добавить объект без установленного Id, то EF в качесте временного значения будет использовать значение по умолчанию, то есть В итоге при добавление более одного объекта в бд мы получим ошибку:
using (ApplicationContext db = new ApplicationContext()) < db.Users.Add(new User < Name = "Tom" >); db.Users.Add(new User < Name = "Alice" >); // Ошибка db.SaveChanges(); var users = db.Users.ToList(); foreach (var user in users) Console.WriteLine($" - "); >
В этом случае нам надо будет устанавливать Id:
using (ApplicationContext db = new ApplicationContext()) < db.Users.Add(new User < Name = "Tom" >); db.Users.Add(new User < Name = "Alice" >); db.SaveChanges(); var users = db.Users.ToList(); foreach (var user in users) Console.WriteLine($" - "); >
Если мы хотим, чтобы база данных, наоборот, сама генерировала значение, то в атрибут надо передавать значение DatabaseGeneratedOption.Identity :
public class User < [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id < get; set; >public string Name < get; set; >>
Но в данном случае для свойства Id это значение избыточно, так как значение генерируется по умолчанию.
Fluent API
Отключение автогенерации значения для свойства:
public class ApplicationContext : DbContext < public DbSetUsers < get; set; >public ApplicationContext() < Database.EnsureDeleted(); Database.EnsureCreated(); >protected override void OnModelCreating(ModelBuilder modelBuilder) < modelBuilder.Entity().Property(b => b.Id).ValueGeneratedNever(); > protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) < optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=helloappdb;Trusted_Connection=True;"); >> public class User < public int Id < get; set; >public string Name < get; set; >>
Значения по умолчанию
Для свойств, которые не представляют ключи и для которых не устанавливается значения, используются значения по умолчанию. Например, для свойств типа int это значение 0. С помощью метода HasDefaultValue() можно переопределить значение по умолчанию, которое будет применяться после добавления объекта в базу данных:
public class ApplicationContext : DbContext < public DbSetUsers < get; set; >public ApplicationContext() < Database.EnsureDeleted(); Database.EnsureCreated(); >protected override void OnModelCreating(ModelBuilder modelBuilder) < modelBuilder.Entity().Property(u => u.Age).HasDefaultValue(18); > protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) < optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=helloappdb;Trusted_Connection=True;"); >> public class User < public int Id < get; set; >public string Name < get; set; >public int Age < get; set; >>
В этом случае, если мы не укажем значение для свойства Age, то ему будет присвоено значение 18:
using (ApplicationContext db = new ApplicationContext()) < User user1 = new User() < Name = "Tom">; Console.WriteLine($"Age: "); // 0 db.Users.Add(user1); db.SaveChanges(); Console.WriteLine($"Age: "); // 18 >
На уровне базы данных это будет проявляться в установке параметра DEFAULT:
CREATE TABLE [dbo].[Users] ( [Id] INT IDENTITY (1, 1) NOT NULL, [Age] INT DEFAULT (18) NOT NULL, [Name] NVARCHAR (MAX) NULL, CONSTRAINT [PK_Users] PRIMARY KEY CLUSTERED ([Id] ASC) );
HasDefaultValueSql
Метод HasDefaultValueSql() также определяет генерацию значения по умолчанию, только само значение устанавливается на основе кода SQL, который передается в этот метод.
Например, пусть в классе пользователя будет свойство CreatedAt, которое представляет дату занесения пользователя в базу данных:
using System; public class User < public int Id < get; set; >public string Name < get; set; >public int Age < get; set; >public DateTime CreatedAt < get; set; >>
Для генерации значения этого свойства в базе данных можно вызывать функцию GETDATE() :
public class ApplicationContext : DbContext < public DbSetUsers < get; set; >public ApplicationContext() < Database.EnsureDeleted(); Database.EnsureCreated(); >protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) < optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=helloappdb;Trusted_Connection=True;"); >protected override void OnModelCreating(ModelBuilder modelBuilder) < modelBuilder.Entity() .Property(u => u.CreatedAt) .HasDefaultValueSql("GETDATE()"); > >
В метод HasDefaultValueSql() передается SQL-выражение, которые вызывается при добавлении объекта User в базу данных.
Вычисляемые столбцы
Столбцы могут иметь значение, которое вычисляется на основании остальных столбцов. Например, пусть модель User имеет свойства для хранения имени и фамилии:
public class User < public int Id < get; set; >public string Name < get;>public string FirstName < get; set; >public string LastName < get; set; >public int Age < get; set; >>
А свойство Name должно представлять объединение свойств FirstName и LastName. И через Fluent API с помощью метода HasComputedColumnSql() можно установить в бд SQL-выражение, которое будет устанавливать значение столбца Name на основании столбцов FirstName и LastName:
public class ApplicationContext : DbContext < public DbSetUsers < get; set; >public ApplicationContext() < Database.EnsureDeleted(); Database.EnsureCreated(); >protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) < optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=helloappdb;Trusted_Connection=True;"); >protected override void OnModelCreating(ModelBuilder modelBuilder) < modelBuilder.Entity() .Property(u => u.Name) .HasComputedColumnSql("[FirstName] + ' ' + [LastName]"); > >
using (ApplicationContext db = new ApplicationContext()) < User user1 = new User() < FirstName = "Tom", LastName="Smith", Age=36 >; Console.WriteLine(user1.Name); // до добавления Name имеет значение по умолчанию db.Users.Add(user1); db.SaveChanges(); Console.WriteLine(user1.Name); // Tom Smith >
Автоматически реализуемые свойства (Руководство по программированию на C#)
Автоматически реализованные свойства делают объявление свойств более кратким, если дополнительная логика не требуется в методах доступа к свойствам. Они также позволяют клиентскому коду создавать объекты. При объявлении свойства, как показано в следующем примере, компилятор создает закрытое анонимное резервное поле, которое может быть доступно только через методы доступа get и set свойства. init Методы доступа также можно объявить как автоматически реализованные свойства.
Пример
В следующем примере показан простой класс, имеющий несколько автоматически реализуемых свойств.
// This class is mutable. Its data can be modified from // outside the class. public class Customer < // Auto-implemented properties for trivial get and set public double TotalPurchases < get; set; >public string Name < get; set; >public int CustomerId < get; set; >// Constructor public Customer(double purchases, string name, int id) < TotalPurchases = purchases; Name = name; CustomerId = id; >// Methods public string GetContactInfo() < return "ContactInfo"; >public string GetTransactionHistory() < return "History"; >// .. Additional methods, events, etc. > class Program < static void Main() < // Initialize a new object. Customer cust1 = new Customer(4987.63, "Northwind", 90108); // Modify a property. cust1.TotalPurchases += 499.99; >>
В интерфейсах невозможно объявлять автоматически реализуемые свойства. Автоматически реализуемые свойства объявляют резервное поле частного экземпляра, а интерфейсы могут не объявлять поля экземпляров. Объявление свойства в интерфейсе без определения тела приводит к объявлению свойства с методами доступа, которые должны реализовываться каждым типом, реализующим этот интерфейс.
Вы можете инициализировать автоматически реализованные свойства аналогично полям:
public string FirstName < get; set; >= "Jane";
Класс, который показан в предыдущем примере, является изменяемым. Клиентский код может изменить значения в объектах после создания. В сложных классах, которые содержат значительные возможности (методы) и данные, часто необходимо иметь открытые свойства. Но для небольших классов или структур, которые просто инкапсулируют набор значений (данных) без какого-либо поведения (или с минимальным поведением), следует использовать один из следующих параметров, чтобы сделать объекты неизменяемыми:
- Объявите только метод доступа get (неизменяемое значение везде, за исключением конструктора).
- Объявите методы доступа get и init (неизменяемое значение везде, за исключением создания объекта).
- Объявите метод доступа set с атрибутом private (неизменяемое значение для потребителей).
См. также
- Использование автоматически реализованных свойств (правило стиля IDE0032)
- Свойства
- Модификаторы
Совместная работа с нами на GitHub
Источник этого содержимого можно найти на GitHub, где также можно создавать и просматривать проблемы и запросы на вытягивание. Дополнительные сведения см. в нашем руководстве для участников.