语言快捷方式
public string Code
{
get;
set;
}
在C#中定义普通属性时节省了一些输入。
然而,我发现自己编写的是高度重复的,不是非常简单的属性代码,仍然遵循明确的模式,例如:
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的全局更改无法追溯更改现有属性代码。
答案 0 :(得分:8)
这被称为Aspect Oriented Programming(AOP)。
斯科特汉塞尔曼最近接受了LinFu的创始人菲利普劳罗亚诺的采访。 (link)
根据您的需要,有许多AOP工具。
最后,使用上述工具对INotifyPropertyChanged类进行了一些实现:
2013年更新:由于这个原始答案,我遇到了另一种解决方案,可以轻松完成我需要的所有工作。
PropertyChanged.Fody(以前称为NotifyPropertyWeaver)是一个后编译IL编织器,它会自动为您插入属性更改代码。现在,这是我对INotifyPropertyChanged的首选解决方案。
答案 1 :(得分:3)
这是我嘲笑的一种练习。最初的灵感来自Jon Skeet的blog post。
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
然后执行相等性检查并调用实际更改属性的lambda并调用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>
答案 2 :(得分:2)
我自己没有这样做,但我已经看到了一个依赖注入框架用于这个特定的任务。
Goes and Googles
Ahaha!
看来,使用Unity DI framework,您可以将INotifyPropertyChanged
注入自动属性。看看这篇精彩的博文:http://shecht.wordpress.com/2009/12/12/inotifypropertychanged-with-unity-interception-aop/
这让我想起了最近的HanselMinutes,斯科特正在与一个关于面向方面编程(AOP)的人谈论这种类型的注射非常常见。
答案 3 :(得分:1)
我讨厌写那段代码!
过去,为了解决这个问题,我已经实现了一个代码生成器来生成一个带有属性定义的partial
类。
答案 4 :(得分:1)
查看NotifyPropertyWeaver:https://github.com/SimonCropp/NotifyPropertyWeaver
答案 5 :(得分:0)
感谢大家的回复。我赞成了有用的答案。然而,经过相当多的研究,我开始相信最好的答案(至少对我和我开发软件的方式)是在Visual Studio中对类进行建模,并使用T4代码生成实现属性的部分类代码。
答案 6 :(得分:-1)
一种非常常见的模式。片段是好的,但男孩,如果MS为自动属性更改通知创建了一些语法糖,那不是很好....
像......那样的东西。
public string Code { get; setwithnotify; }
那确实非常好。
答案 7 :(得分:-6)
回答有关重复代码的一般问题,而不仅仅是财产变更通知案例:
不确定。这是宏的一个完美案例。
等等哦。 C#没有宏。当然,宏是邪恶的,并不是任何编程问题的最佳解决方案。除非您在构建中插入预处理器。