Ярлык языка
public string Code
{
get;
set;
}
сохраняет немного ввода при определении тривиальных свойств в C#.
Однако я пишу очень повторяющийся, not-quite-as-trivial код свойства, который все еще следует за ясным шаблоном, например.
public string Code
{
get { return code; }
set
{
if (code != value)
{
code = value;
NotifyPropertyChanged("Code");
}
}
}
Я могу, конечно, определить отрывок Visual Studio для сокращения ввода. Однако, если я должен добавить что-то к своему шаблону, я должен возвратиться и изменить довольно мало существующего кода.
Существует ли более изящный подход? Действительно ли отрывок является лучшим способом пойти?
ОБНОВЛЕНИЕ:
Как быстрое улучшение для прямо сейчас, я отредактировал (после создания резервного копирования)
C:\Program Files\Microsoft Visual Studio 10.0\VC#\Snippets\1033\Refactoring\EncapsulateField.snippet
(путь является для VS 2010),
отразить мой текущий шаблон. Теперь, встроенный инструмент рефакторинга использует мой шаблон для создания свойства из поля. Недостатки: Глобальное изменение для Visual Studio, не может задним числом изменить существующий код свойства.
Это известно как Aspect Oriented Программирование (AOP).
Скотт Хансельман недавно взял интервью на эту тему с создателем LinFu Филипом Лауреано. ( ссылка )
Существует ряд инструментов АОП, в зависимости от ваших потребностей.
И, наконец, некоторые реализации класса INotifyPropertyChanged с использованием вышеуказанных инструментов:
Обновление 2013 г .: После этого исходного ответа я нашел другое решение это делает все, что мне нужно, очень легко.
PropertyChanged.Fody (ранее NotifyPropertyWeaver) - это программа-ткач на IL после компиляции, которая автоматически вставляет для вас код изменения свойства. Теперь это мое предпочтительное решение для INotifyPropertyChanged.
Я не делал этого сам, но я видел, как фреймворк для введения зависимостей используется для этой конкретной задачи.
Идет и гуглит
Ахаха!
Похоже, используя Unity DI framework, вы можете внедрить INotifyPropertyChanged
в автоматическое свойство. Взгляните на эту замечательную статью в блоге: http://shecht.wordpress.com/2009/12/12/inotifypropertychanged-with-unity-interception-aop/
Это напомнило мне о недавнем выпуске HanselMinutes, где Скотт говорит с парнем об аспектно-ориентированном программировании (AOP), где этот тип инъекции очень часто встречается.
Вот то, что я придумал в качестве упражнения. Изначально вдохновила запись в блоге Jon Skeet.
public static class ObjectExtensions {
public static string GetPropertyNameAndValue<T>(this T obj, out object value) {
System.Reflection.PropertyInfo[] objGetTypeGetProperties = obj.GetType().GetProperties();
if(objGetTypeGetProperties.Length == 1) {
value = objGetTypeGetProperties[0].GetValue(obj, null);
return objGetTypeGetProperties[0].Name;
} else
throw new ArgumentException("object must contain one property");
}
}
class Whatever {
protected void ChangeProperty<T>(object property, T newValue, Action change) {
object value;
var name = property.GetPropertyNameAndValue(out value);
if(value == null && newValue != null || value != null && !value.Equals(newValue)) {
change();
OnPropertyChanged(name);
}
}
private string m_Title;
public string Title {
get { return m_Title; }
set {ChangeProperty(
new { Title }, //This is used to dynamically retrieve the property name and value
value, // new value
() => m_Title = value); //lambda to change the value
}
}
}
Это лучшее, что я смог придумать. Удар по производительности во время выполнения может быть довольно большим, но я не проверял это.
Небольшое пояснение к вышеприведенному решению. new { Title }
создает анонимный объект, и благодаря проекции (введенной в .NET 3.5) вновь созданный объект имеет единственное свойство Title
и значение, которое является значением свойства Title
исходного объекта.
GetPropertyNameAndValue
- это функция, которая делает всю интересную работу - извлекает имя и значение свойства из анонимного объекта. ChangeProperty
затем выполняет проверку равенства и вызывает лямбду, которая действительно изменяет свойство, а также вызывает NotifyPropertyChanged
.
В качестве альтернативы можно просто сделать фрагмент следующего содержания:
<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Title>propfullinotify</Title>
<Shortcut>propfullinotify</Shortcut>
<Description>Code snippet for property and backing field with INotifyPropertyChanged</Description>
<Author>Microsoft Corporation</Author>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal>
<ID>type</ID>
<ToolTip>Property type</ToolTip>
<Default>int</Default>
</Literal>
<Literal>
<ID>property</ID>
<ToolTip>Property name</ToolTip>
<Default>MyProperty</Default>
</Literal>
<Literal>
<ID>field</ID>
<ToolTip>The variable backing this property</ToolTip>
<Default>myVar</Default>
</Literal>
</Declarations>
<Code Language="csharp">
<![CDATA[private $type$ $field$;
public $type$ $property$
{
get { return $field$;}
set {
if ($field$ != value)
{
$field$ = value;
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("$property$"));
}
}
}
$end$]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>
очень распространенный образец. Сниппет в порядке, но, боже, было бы здорово, если бы MS создала некоторый синтаксический сахар для уведомлений об автоматическом изменении свойств ....
Что-то вроде ....
public string Code { get; setwithnotify; }
Это действительно было бы очень хорошо.
Я ненавижу писать этот код!
В прошлом, чтобы справиться с этой проблемой, я реализовал генератор кода для создания класса partial
с определениями свойств.
Чтобы ответить на общий вопрос о повторяющемся коде, а не только на случай уведомления об изменении свойства:
Конечно. Это идеальный случай для макроса.
Ой, погоди. В C # нет макросов. Потому что, конечно, макросы - зло и не лучшее решение любой проблемы программирования.
Если вы не добавите препроцессор в свою сборку.
Спасибо всем за ответы. Я поддержал полезные ответы. Однако после небольшого исследования я пришел к выводу, что лучший ответ (по крайней мере, для меня и того, как я разрабатываю программное обеспечение) - моделировать классы в Visual Studio и использовать T4 для создания кода частичных классов, реализующих свойство код.