Как стать автором
Обновить

Комментарии 10

Полная иммутабельность, увы, не дана нам прямо из коробки.

А как же init аксессор появившийся в C# 9.0? Следующий код позволит проинициализировать свойства при создании объекта/структуры, но при попытке изменить свойство внутри или снаружи объекта еще перед компиляцией покажет что это невозможно.

namespace cicd_test
{
    public class SomeClass
    {
        public int MyProperty { get; init; }
				
        // Этот метод не даст приложению собраться
        public void SetProp(int i) => MyProperty = i;
    }

    public struct SomeStruct
    {
        public int MyProperty { get; init; }

      	// Этот метод не даст приложению собраться
        public void SetProp(int i) => MyProperty = i;
    }

    public class Test
    {
        // Тут все нормально
        SomeClass someClass = new()
        {
            MyProperty = 0
        };
      
      	// Тоже покажет ошибку и не даст скомпилироваться
        someClass.MyProperty = 1;
				
      	// Тут все нормально
        SomeStruct someStruct = new()
        {
            MyProperty = 0
        };
      
      	// Тоже покажет ошибку и не даст скомпилироваться
        someStruct.MyProperty = 1;
    }
}

В более ранних версиях можно явно использовать readonly поля, а в свойстве только get.

А вообще насколько я понимаю в .NET языках иммутабельность не значит, что нельзя менять значения и ай-яй-яй. Это значит, что при вызове изменения - создаётся и возвращается новое значение.

Вы что-то странное помните

Да, немного неправильно сказал. Ай-яй-яй делает компилятор. Под вызовом изменений я имел ввиду методы типа Add для коллекций и with для рекордов. Присваивание естественно нельзя

Имхо, задача гораздо лучше решается с помощью кастомного Roslyn Analyzer: находим все классы, помеченные неким маркерным атрибутом IImmutable, пробегаемся по списку их полей и проверяем типы (возможно рекурсивно).


В отличие от решения в статье, анализатор:


  • Будет работать статически на этапе компиляции
  • Не потребует написания кошмарного кода вида MethodBase.GetCurrentMethod().Name.Substring(4)
НЛО прилетело и опубликовало эту надпись здесь

В чем сложность определить ImmutableClass?

public class SimpleImmutableClass
{
public SimpleImmutableClass(
string firstName, string lastName, IEnumerable<string> items
)

{
FirstName = firstName;
LastName = lastName;
Items = items.ToList();
}

//Неявные приватные сеттеры
public string LastName { get; }
public string FirstName { get; }
public IReadOnlyList<string> Items { get; }
}

Статью писал человек совсем далёкий от Net.

Все примеры кривые, для коллекций например есть IReadOnlyCollection. Есть как верно подмечено инициаторы.

Да и всё уже давно придумано за нас.

То-есть написать класс с конструктором и приватными сеттерами это ой-ой-ой какая жуть, а наогородить кучу кода с рефлексией это респектос?

Подход конечно огонь!!!!

Если уж рефлексируете то хоть кешируйте результаты, по секрету скажу у одного и того же типа обьёктов полей в рантайме не прибавиться))))

А что мешает возвращать в геттере коллекцию .AsReadOnly()?

Я бы не назвал этот подход "изящным решением".

Имхо гораздо проще реализовать иммутабельность через конструктор с приватными сеттерами, если это допустим доменная сущность и или объект-значение, либо вообще без сеттеров если это DTO.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий