Правильное использование свойств C#

Рейтинг: 1Ответов: 3Опубликовано: 06.08.2023

Часто вижу разную реализацию одного и того же простого кода

// 1
private int _health;
public int Health { get => _health; }
// 2 
public int Health { get; private set; }

По сути, это одно и то же? Стоит ли использовать что-то конкретное или никакой разницы нет?

Ответы

▲ 3Принят

Работать с полем, логически выделенном для публикации через свойство (backing field) за пределами геттера и сеттера - плохой тон, усложняющий отладку кода и увеличивающий вероятность появления ошибок.

Если свойство неизменяемое, то это должно быть видно сразу, например должен отсутствовать сеттер.

Технически разницы между полными и автосвойствами никакой нет. Для автосвойства поле выделит компилятор.

▲ 1

Да, это одно и то же. Разницы быть не должно и при оптимизирующей компиляции.

Второй вариант выглядит более предпочтительным.

Разница может появиться, если вместо типа int (а в общем же вопрос не ограничивается одним типом) будет структура. Тогда в первом случае можно будет менять структуру через поле, а во втором - нельзя.

▲ 0
  1. В версиях языка до С#6 отсутствовала возможность указать инициализатор для auto-implemented properties, поэтому им приходилось всегда задавать начальное значение в конструкторе либо (в случае свойств только для чтения), делать readonly поле с инициализацией в конструкторе и отдельно свойство для чтения. В C#6 этот недостаток устранили и появилась возможность указывать инициализатор public int Health { get; private set; } = 42;

  2. auto-implemented properties не могут быть использованы при создании классов с явно заданным распределением памяти, так как для них нельзя указать обязательный атрибут смещения данных:

using System;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Explicit, Size=16, CharSet=CharSet.Ansi)]
class MyClass
{
    [FieldOffset(0)]public ushort first;
    [FieldOffset(2)]public ushort second;
    // ok
    [FieldOffset(4)]private int _health; 
    public int Health { get => _health; }
    // error FieldOffset не применим
    [FieldOffset(4)]public int Health { get; private set; }
    // error отсутствует обязательный FieldOffset
    public int Health { get; private set; }
}