Вопрос

У меня есть класс с кучей свойств, которые выглядят примерно так:

public string Name
{
    get { return _name; }
    set { IsDirty = true; _name = value; }
}

Было бы намного проще, если бы я мог полагаться на C # 3.0 для создания резервного хранилища для них, но есть ли какой-либо способ исключить IsDirty = true;чтобы я мог написать свои свойства примерно так и при этом получать то же поведение:

[MakesDirty]
public string Name { get; set; }
Это было полезно?

Решение

Нет.Не без написания значительно большего количества (загадочного?) кода, чем исходная версия (Вам пришлось бы использовать отражение, чтобы проверить наличие атрибута в свойстве, а что нет..я упоминал, что это "медленнее")..Это тот вид дублирования, с которым я могу жить.

MS испытывает такую же потребность в вызывающие события при изменении свойства.INotifyPropertyChanged - это жизненно важный интерфейс для уведомлений об изменениях.Каждая реализация, которую я уже видел делает

set
{ 
  _name = value; 
  NotifyPropertyChanged("Name"); 
}

Если бы это было возможно, я бы подумал, что у этих умных ребят из MS уже было бы что-то подобное..

Другие советы

Вы могли бы попробовать настроить фрагмент кода, чтобы упростить их создание.

Если вы действительно хотите пойти этим путем, изменить то, что делает код, используя атрибут, есть несколько способов сделать это, и все они связаны с AOP (аспектно-ориентированное программирование).Проверьте Постшарповый, который является послекомпилятором, который может изменять ваш код на этапе после компиляции.Например, вы могли бы настроить один пользовательский атрибут для ваших свойств (или aspect, как это называется в AOP), который вводит код внутри установщиков свойств, который помечает ваши объекты как грязные.Если вам нужны несколько примеров того, как это достигается, вы можете ознакомиться с их Руководства.

Но будьте осторожны с AOP и потому, что вы можете так же легко создать больше проблем, используя его, которые вы пытаетесь решить, если не используете его правильно.

Существует больше фреймворков AOP, некоторые из которых используют post-компиляцию, а некоторые используют механизмы перехвата методов, которые присутствуют в .Net, последние имеют некоторые недостатки в производительности по сравнению с первыми.

Нет, когда вы используете автоматические свойства, у вас нет никакого контроля над реализацией.Лучший вариант - использовать инструмент создания шаблонов, фрагменты кода или создать частное значение setValue<T>(ref T backingField, значение T), которое инкапсулирует логику настройки.

private void SetValue<T>(ref T backingField, T value)
{
   if (backingField != value)
   {
      backingField = value;
      IsDirty = true;
   }
}

public string Name
{
   get
   {
      return _name;
   }
   set
   {
      SetValue(ref _name, value);
   }
}

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

Я могу порекомендовать использовать Корпоративная библиотека для этой цели.Блок приложений политики предоставляет инфраструктуру для выполнения "чего-то" (что-то = вы можете закодировать это самостоятельно), например, всякий раз, когда вы вводите / выходите из метода.Вы можете управлять поведением с помощью атрибутов.Примите это как подсказку и подробно ознакомьтесь с документацией enterprise library.

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

Вам нужно было бы использовать Отражение для идентификации изменений свойств, чего на самом деле нет это дорого, если только вы не делаете этого в большом количестве!

Предостережение:Вы не смогли бы определить, было ли свойство изменено ОБРАТНО со значения, отличного от значения по умолчанию, на значение по умолчанию.

Я бы сказал, что лучший способ решить эту проблему - использовать аспектно-ориентированное программирование (AOP).Матс Хеландер сделал напишите об этом в InfoQ.Статья немного сумбурная, но за ней можно следить.Существует множество различных продуктов, которые выполняют AOP в сетевом пространстве .Я рекомендую PostSharp.

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

В противном случае вы рассматриваете возможность использования событий maybe.Вам все равно пришлось бы добавлять событие к каждому методу set, но преимущество было бы в том, что вы не прописываете жестко, что делать с грязными наборами для каждого свойства, и можете контролировать в одном месте, что нужно делать.Это, по крайней мере, привело бы к немного большему повторному использованию кода.

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

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

class A
{
    [Foo]
    public int Property1{get; set;}
    public int Property2{get {return variable;} set{ Property1 = value; variable = value; }
}

Когда property1 вызывается из другого класса, будет вызван ваш прокси-сервер.Но если другой класс вызывает property2, даже если набор property2 вызовет property1, прокси-сервер не будет вызван (прокси-сервер не нужен, когда вы находитесь в самом классе).

Существует много примеров кода с использованием ContextBoundObjects, ознакомьтесь с ним.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top