我有一个类有一堆看起来像这样的属性:
public string Name
{
get { return _name; }
set { IsDirty = true; _name = value; }
}
如果我可以依靠 C# 3.0 为这些生成后备存储,那会容易得多,但是有什么方法可以排除 IsDirty=true; 这样我就可以编写类似这样的属性并且仍然得到相同的行为:
[MakesDirty]
public string Name { get; set; }
我有一个类有一堆看起来像这样的属性:
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(面向方面的编程)有关。查看PostSharp,它是一个后编译器,可以在编译后的步骤中修改您的代码。例如,您可以为您的属性(或方面,它在 AOP 中的调用方式)设置一个自定义属性,该属性将代码注入属性设置器中,将您的对象标记为脏。如果您想了解如何实现这一点的一些示例,您可以查看他们的教程。
但是要小心 AOP,因为如果使用不当,您可以轻松地使用它来创建更多您试图解决的问题。
有更多的 AOP 框架,一些使用后编译,一些使用 .Net 中存在的方法拦截机制,与第一个相比,后者有一些性能缺陷。
不,当您使用自动属性时,您无法控制实现。最好的选择是使用模板工具、代码片段或创建<T
封装 setter 逻辑的私有 SetValue >(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);
}
}
另一种选择可能是代码生成器,例如 codesmith 来自动创建属性。如果您创建的属性是数据库表中的列,这将特别有用
上下文绑定对象。如果创建扩展上下文绑定对象的类并创建 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 的示例代码,请查看。
为此,我可以推荐使用Enterprise Library。例如,每当您输入/退出方法时,策略应用程序块都会提供基础架构来执行“某事”(某事 = 您可以自己编写代码)。您可以使用属性控制行为。以此为提示,详细了解企业库的文档。
有一个可以分配给属性的 DefaultValueAttribute,这主要由设计器工具使用,因此它们可以指示属性何时更改,但是,它可能是描述属性默认值的一种“整洁”方式,从而能够识别它是否已更改。
您需要使用反射来识别属性更改 - 这实际上并没有那么昂贵,除非您做很多事情!
警告:您无法判断属性是否已从非默认值更改为默认值。
我想说解决这个问题的最好方法是使用面向方面的编程(AOP)。Mats Helander在 InfoQ 上对此做了一篇文章。这篇文章有点乱,但可以遵循。有许多不同的产品在 .NET 空间中执行 AOP,我推荐 PostSharp。
如果您确实使用属性,我相当肯定您将不得不滚动自己的逻辑来推断它们的含义以及如何处理它们。无论使用您的自定义类对象,都必须有一种方法来执行这些属性操作/检查,最好是在实例化时。
否则,您正在考虑使用可能的事件。您仍然必须将事件添加到每个 set 方法,但这样做的好处是您无需硬编码如何处理每个属性上的脏集,并且可以在一个地方控制要做什么。这至少会引入更多的代码重用。