.NET лучшие практики использования неизменяемого объекта? Должен ли я использовать их как можно больше? - PullRequest
0 голосов
/ 01 апреля 2010

скажем, у меня есть простой объект, такой как

class Something
{
   public int SomeInt { get; set; }
}

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

class ImmutableSomething
{
   public int SomeInt { get { return m_someInt; } }
   private int m_someInt = 0;

   public void ChangeSomeInt(int newValue)
   {
       m_someInt = newvalue;
   }
}

Что ты считаешь?

Ответы [ 5 ]

7 голосов
/ 01 апреля 2010

То, что вы изображаете, не является неизменным объектом; простое перемещение кода set в специальный метод установки не делает объект неизменным. Неизменяемый объект по определению не может изменить , поэтому тот факт, что вы можете изменить значение любого из свойств или полей объекта, означает, что он не является неизменным.

В терминах «быстрее» или «лучше» неизменяемые объекты не являются по своей природе быстрее или «лучше», чем изменяемые объекты; в них нет ничего особенного, кроме того факта, что вы не можете изменять никакие значения.

6 голосов
/ 01 апреля 2010

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

public class ImmutableSomething
{
    private readonly int _someInt;
    public int SomeInt
    {
        get
        {
            return _someInt;
        }
    }

    public ImmutableSomething(int i)
    {
        _someInt = i;
    }

    public ImmutableSomething Add(int i){
        return new ImmutableSomething(_someInt + i);
    }
}

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

Код, созданный из неизменяемых объектов, можно легко распараллелить, потому что не существует доступного для записи общего состояния. Если какой-то другой поток получает ваше Значение и хочет что-то с ним сделать, он не может. Любое его изменение приводит к созданию нового объекта с новым местом в памяти только для этого объекта.

Так что, как только вы разберетесь со значениями, вы можете делать некоторые специальные вещи, такие как интернирование, что и делает .NET со строками. Поскольку «Hello World» является значением и никогда не изменится, одна ссылка на «Hello World» так же хороша, как и любая другая, поэтому вместо того, чтобы иметь «Hello World» в сотне слотов в памяти, вы получите его в одном слоте и установите все ссылки на «Hello World», чтобы указать на этот один слот. Таким образом, вы получаете большой выигрыш на стороне памяти, но платите штраф за производительность, потому что всякий раз, когда вы создаете новую строку, вы должны проверять внутренний пул, чтобы убедиться, что он еще не существует.

3 голосов
/ 16 июня 2012

Основным преимуществом глубоко неизменяемых объектов является то, что очень просто сделать «снимок» их свойств - просто скопируйте ссылку на объект. Независимо от того, насколько большим или сложным может быть объект, можно «сделать снимок» всего этого, просто скопировав одну ссылку.

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

Хотя неизменяемые объекты гораздо проще «снимать», чем изменяемые, иногда, учитывая неизменяемый объект, иногда бывает трудно создать экземпляр, который похож на первый, за исключением некоторых незначительных изменений. В этом отношении с изменяемыми объектами иногда легче работать. Иногда может быть полезно скопировать данные из неизменяемого объекта в изменяемый объект, изменить его, а затем создать новый неизменяемый объект, который содержит измененные данные. К сожалению, нет никаких общих способов автоматизировать такое преобразование с помощью классов. Однако есть альтернатива.

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

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

2 голосов
/ 01 апреля 2010

Это не неизменный объект. Неизменная версия этого будет что-то вроде

class ImmutableSomething : ISomething
{
    public readonly int SomeInt;

    public ImmutableSomething(int i)
    {
        SomeInt = i;
    }

    public ImmutableSomething AddValue(int add)
    {
        return new ImmutableSomething(this.SomeInt + add);
    }
}

Основным преимуществом неизменяемого объекта является то, что сам объект никогда не изменится, поэтому вы не рискуете, чтобы одна часть вашего кода изменила базовые значения, особенно в ситуациях с многопоточностью, но в целом это применимо. Эти гарантии часто делают объекты «лучше», потому что вы знаете, чего ожидать, но нет ничего, что делает неизменяемые по своей природе «быстрее», чем изменяемые объекты.

Например, DateTimes являются неизменяемыми, поэтому вы можете делать такие вещи, как

DateTime someReferenceTime = DateTime.Now;

myBusinessLayer.DoABunchOfProcessingBasedOnTime(someReferenceTime);

// Here you are guaranteed that someReferenceTime has not changed, and you can do more with it.

В сравнении с чем-то вроде

StringBuilder sb = new StringBuilder("Seed");

myBusinessLayer.DoStuffBasedOnStringBuilder(sb);

// You have no guarantees about what sb contains here.
0 голосов
/ 01 апреля 2010

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

Но в неизменных объектах нет ничего волшебного, что делает их по своей природе более быстрыми.

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