Изменение значения свойства без нарушения неизменности - PullRequest
3 голосов
/ 01 марта 2020

Я довольно озадачен самым чистым способом поддержания неизменности.

Это самый простой и самый глупый вариант, который я получил до сих пор, но мне все еще интересно, нет ли менее многословного способа достичь этого

class MyClass
{
    public int Property1 { get; }
    public string Property2 { get; }

    public MyClass CopyWith(int? property1 = default, string property2 = default)
    {
        return new MyClass
        {
            Property1 = property1 ?? Property1,
            Property2 = property2 ?? Property2
        };
    }
}

class Program
{
    static void Main()
    {
        var myObj = new MyClass { Property1 = 123, Property2 = "123" };

        var myModifiedObj = myObj.CopyWith(property2: "456");
    }
}

Методы расширения с обобщениями будут включать ОЧЕНЬ много размышлений, но я все еще убежден, что я слишком много думаю, и, возможно, есть более простое решение, которое я упускаю ...

Ответы [ 3 ]

3 голосов
/ 01 марта 2020

Чтобы иметь неизменный класс , сначала нужно убедиться, что свойства недоступны извне . Поэтому я бы изменил его на:

class MyClass
{
    public int Property1 { get; }
    public string Property2 { get; }

    public MyClass(int prp1, string prp2)
    {
        Property1 = prp1;
        Property2 = prp2;
    }

    public MyClass With(int? property1 = default, string property2 = default) =>
        new MyClass(property1 ?? Property1, property2 ?? Property2);

}

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

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

Это будет выглядеть так:

class MyClass
{
    // until here it is the same as before

    public MyClass WithPrp1(int prp1) => new MyClass(prp1,Property2);
    public MyClass WithPrp2(string prp2) => new MyClass(Property1,prp2);   
}

class Program
{
    static void Main()
    {
        var myObj = new MyClass(123, "123");
        var myModifiedObj = myObj.WithPrp1(456).WithPrp2("789");
    }
}
2 голосов
/ 04 марта 2020

C# (к сожалению) весьма ограничен в том, что касается объявления / изменения неизменяемых типов - ходили разговоры об неизменяемых записях, поступающих в C # 8, но этого не произошло.

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

class MyClass : IImmutable
{
  public MyClass(int property1, string property2) { Property1 = property1; Property2 = property2; }
  public int Property1 { get; }
  public string Property2 { get; }
}

void F()
{
  var myObj = new MyClass(123, "123");
  var myModifiedObj = myObj.With(x => x.Property2, "456");
}

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

0 голосов
/ 01 марта 2020

Сделайте ваши установщики свойств private, затем создайте метод перегрузки для каждого свойства.

public class MyClass
{
    public int Property1 { get; }

    public string Property2 { get; }

    public MyClass(int property1, string property2)
    {
        Property1 = property1;
        Property2 = property2;
    }

    public MyClass CopyWith(int property1) => new MyClass(property1, Property2);

    public MyClass CopyWith(string property2) => new MyClass(Property1, property2);

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...