Этот метод основан на наборе различных понятий, представленных в этой теме. Я думал, что выложу это для всех, кто ищет способ сделать это чисто и эффективно, как и я сам.
Ключ этой гибридной концепции заключается в следующем:
- Вы не хотите дублировать данные, чтобы избежать вздутия и нехватки ресурсов;
- Вы хотите знать, когда свойства объекта изменились с данного исходного / чистого состояния;
- Вы хотите, чтобы флаг IsDirty был как точным, так и требующим небольшого времени / мощности обработки для возврата значения; и
- Вы хотите быть в состоянии указать объекту, когда снова считать себя чистым. Это особенно полезно при сборке / работе в пользовательском интерфейсе.
Учитывая эти требования, это то, что я придумал, и, похоже, оно отлично работает для меня, и стало очень полезным при работе с пользовательским интерфейсом и точном отслеживании изменений пользователя. Я также разместил ниже «Как использовать», чтобы показать вам, как я использую это в пользовательском интерфейсе.
Объект
public class MySmartObject
{
public string Name { get; set; }
public int Number { get; set; }
private int clean_hashcode { get; set; }
public bool IsDirty { get { return !(this.clean_hashcode == this.GetHashCode()); } }
public MySmartObject()
{
this.Name = "";
this.Number = -1;
MakeMeClean();
}
public MySmartObject(string name, int number)
{
this.Name = name;
this.Number = number;
MakeMeClean();
}
public void MakeMeClean()
{
this.clean_hashcode = this.Name.GetHashCode() ^ this.Number.GetHashCode();
}
public override int GetHashCode()
{
return this.Name.GetHashCode() ^ this.Number.GetHashCode();
}
}
Это достаточно просто и отвечает всем нашим требованиям:
- Данные НЕ дублируются для грязной проверки ...
- Это учитывает все сценарии изменения свойств (см. Сценарии ниже) ...
- Когда вы вызываете свойство IsDirty, выполняется очень простая и маленькая операция Equals, которая полностью настраивается с помощью переопределения GetHashCode ...
- Вызывая метод MakeMeClean, вы снова получаете чистый объект!
Конечно, вы можете адаптировать это, чтобы охватить кучу разных состояний ... это действительно ваше дело. В этом примере показано, как правильно выполнить операцию флага IsDirty.
Сценарии
Давайте рассмотрим некоторые сценарии для этого и посмотрим, что получится:
Сценарий 1
Новый объект создается с помощью пустого конструктора,
Имя свойства изменяется с "" на "Джеймс",
вызов IsDirty возвращает True! Точная.
Сценарий 2
Новый объект создается с использованием параметров «Джон» и 12345,
Имя свойства меняется с «Джон» на «Джеймс»,
Имя свойства меняется с «Джеймс» на «Джон»,
Call to IsDirty возвращает False. Точно, и нам не нужно было дублировать данные, чтобы сделать это!
Как использовать, пример пользовательского интерфейса WinForms
Это всего лишь пример, вы можете использовать его различными способами в пользовательском интерфейсе.
Допустим, у вас есть две формы ([A] и [B]).
Первая ([A]) - это ваша основная форма, а вторая ([B]) - это форма, которая позволяет пользователю изменять значения в MySmartObject.
Форма [A] и [B] имеет следующее объявленное свойство:
public MySmartObject UserKey { get; set; }
Когда пользователь нажимает кнопку в форме [A], создается экземпляр формы [B], устанавливается его свойство и он отображается в виде диалога.
После возврата формы [B] форма [A] обновляет свое свойство на основе проверки IsDirty формы [B]. Как это:
private void btn_Expand_Click(object sender, EventArgs e)
{
SmartForm form = new SmartForm();
form.UserKey = this.UserKey;
if(form.ShowDialog() == DialogResult.OK && form.UserKey.IsDirty)
{
this.UserKey = form.UserKey;
//now that we have saved the "new" version, mark it as clean!
this.UserKey.MakeMeClean();
}
}
Кроме того, в [B], когда он закрывается, вы можете проверить и запросить пользователя, закрывают ли они форму с несохраненными изменениями в ней, например:
private void BForm_FormClosing(object sender, FormClosingEventArgs e)
{
//If the user is closing the form via another means than the OK button, or the Cancel button (e.g.: Top-Right-X, Alt+F4, etc).
if (this.DialogResult != DialogResult.OK && this.DialogResult != DialogResult.Ignore)
{
//check if dirty first...
if (this.UserKey.IsDirty)
{
if (MessageBox.Show("You have unsaved changes. Close and lose changes?", "Unsaved Changes", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.No)
e.Cancel = true;
}
}
}
Как видно из приведенных выше примеров, это может быть очень полезным, поскольку оно действительно упрощает пользовательский интерфейс.
Предостережения
- Каждый раз, когда вы реализуете это, вы должны настроить его для объекта, который вы используете. Например: нет "простого" общего способа сделать это без использования отражения ... и если вы используете отражение, вы теряете эффективность, особенно в больших и сложных объектах.
Надеюсь, это кому-нибудь поможет.