Подтвердить что ты не робот

Как создать неизменяемые объекты в С#?

В вопросе Рекомендации по проверке шаблонов С#, самый высокий голосовой ответ говорит:

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

Как именно вы создаете неизменяемый объект в С#? Вы используете ключевое слово readonly?

Как именно это будет работать, если вы хотите проверить в конструкторе класса модели, созданного в Entity Framework?

Будет ли это выглядеть ниже?

public partial readonly Person
{
    public Person()
}
4b9b3361

Ответ 1

Интересный вопрос здесь - ваш вопрос из комментариев:

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

Хорошо, рассмотрите вещи, которые уже неизменяемы. Числа неизменны. Как только у вас будет номер 12, он 12. Вы не можете его изменить. Если у вас есть переменная, содержащая 12, вы можете изменить содержимое переменной до 13, но вы меняете переменную, а не цифру 12.

То же самое со строками. "abc" - "abc" , и он никогда не изменяется. Если у вас есть переменная, содержащая "abc" , вы можете изменить ее на "abcd" , но это не изменит "abc" , что изменяет переменную.

Как насчет списка? {12, "abc" } - это список из 12, за которым следует "abc" , и этот список никогда не изменяется. Список {12, "abcd" } - это другой список.

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

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

То есть, если вы мутируете {12, "abc" } на {12, "abcd" }, а затем хотите отбросить мутацию, как вы это делаете? Если список неизменен, вы просто сохраняете оба значения и выбираете, какой из них вы хотите быть "текущим" значением. Если список изменен, тогда вы должны иметь логику отмены, чтобы поддерживать "функцию отмены", которая знает, как отменить мутацию.

Что касается вашего конкретного примера, вы, безусловно, можете создать неизменяемую базу данных. Как вы меняете имя кого-то в своей неизменяемой базе данных? Вы этого не сделаете. Вы создаете новую базу данных, в которой есть нужные вам данные. Трюк с неизменяемыми типами должен делать это эффективно, без копирования миллиардов байтов. Непрерывный дизайн структуры данных требует поиска умных способов совместного использования состояния между двумя почти идентичными структурами.

Ответ 2

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

В С# неизменяемость не выполняется компилятором. Вы просто должны быть осторожны.

Ответ 4

Этот вопрос имеет два аспекта:

  • Неизменяемый тип при создании объекта
  • Неизменяемый тип, когда экземпляр объекта EF

Первый аспект требует такой структуры:

public class MyClass
{
  private readonly string _myString;
  public string MyString
  {
    get
    {
      return _myString;
    }
  }

  public MyClass(string myString)
  {
    // do some validation here

    _myString = myString;
  }
}

Теперь проблема - EF. EF требует бесступенчатого конструктора, а EF должен иметь сетчатые свойства. Я задал очень похожий вопрос здесь.

Ваш тип должен выглядеть так:

public class MyClass
{
  private string _myString;
  public string MyString
  {
    get
    {
      return _myString;
    }
    private set
    {
      _myString = value;
    }
  }

  public MyClass(string myString)
  {
    // do some validation here

    _myString = myString;
  }

  // Not sure if you can change accessibility of constructor - I can try it later
  public MyClass()
  {}
}

Вы также должны сообщить EF о приватном настройке свойства MyString - это настроено в свойствах enitity в файле EDMX. Очевидно, что не будет подтверждения, когда EF материализует объекты из БД. Также вы не сможете использовать такие методы, как ObjectContext.CreateObject(вы не сможете заполнить объект).

Шаблон объекта Entity Object T4 и генерация кода по умолчанию создают метод factory CreateMyClass вместо конструктора с параметрами. Шаблон POCO T4 не генерирует метод factory.

Я не пробовал это сначала с EF Code.

Ответ 5

Объектом неизменяемого значения является объект значения, который нельзя изменить. Вы не можете изменить свое состояние, вам нужно создать новые

Зайдите в блог Эрика Липперта:

Виды неизменности http://blogs.msdn.com/b/ericlippert/archive/2007/11/13/immutability-in-c-part-one-kinds-of-immutability.aspx

Посмотрите

Неизменяемый шаблон объекта на С# - что вы думаете?

Ответ 6

Как именно это будет работать, если вы хотите проверить в конструкторе класса модели, созданного в Entity Framework?

В этом контексте это не сработает, потому что EF требует, чтобы свойства класса сущности были общедоступными, иначе он не сможет его создать.

Но вы можете использовать неизменяемые объекты в своем коде.

Ответ 7

@Eric Lippert Хороший комментарий, но в дополнение к ответу на вопрос:

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

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

И это трудно сделать, потому что эти вещи всегда влияют на вещи неожиданным образом, данные меняются у вас под ногами.

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

Так что да, очень полезная концепция, если вы ненавидите иметь дело с проблемами параллелизма и не имеете слишком много данных для решения. (Например, если 1 МБ данных и обновление 10/сек, то 10 МБ копируемых данных)