Свойства C# с повторяющимся кодом

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

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

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

[MakesDirty]
public string Name { get; set; }

Похоже, это невозможно (спасибо, Гишу), поэтому я буду использовать для этого шаблоны CodeRush. Спасибо, что напомнили мне о сниппетах.

Craig.Nicol 15.09.2008 19:15
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
5
1
1 739
10
Перейти к ответу Данный вопрос помечен как решенный

Ответы 10

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

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

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

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

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

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

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

Амир, технически это решение - однако лично я не думаю, что это хорошее место для применения этого :) Хороший ответ - однако не могу проголосовать за него в контексте этого вопроса. Извините за каламбур :)

Gishu 15.09.2008 19:03
Ответ принят как подходящий

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

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

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

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

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

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

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

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

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

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);
   }
}

Но тогда вам придется дублировать метод SetValue <T> в каждом таком классе. Если вы превратите его в общедоступный статический / служебный метод, вам придется выставить состояние IsDirty .. Не круто :)

Gishu 15.09.2008 19:06

@Gishu: Да, вы бы продублировали вызов SetValue в каждом свойстве и, возможно, в каждом классе. В зависимости от того, как получены ваши расчеты, будет определяться, являются ли SetValue (и, следовательно, IsDirty) общедоступными.

Scott Dorman 15.09.2008 19:18

Это не работает: connect.microsoft.com/VisualStudio/feedback/details/304501/…

NotMe 26.05.2011 18:30

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

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

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

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

Но будьте осторожны с АОП, потому что с его помощью вы можете так же легко создать больше проблем, которые вы пытаетесь решить, если использовать неправильно.

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

PostSharp идеально подходит для подобного сценария!

Pauli Østerø 07.11.2010 21:26

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