我有一个类,其中包含许多如下所示的属性:

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(面向方面​​编程)相关。查看 后锐利, ,这是一个后编译器,可以在编译后步骤中修改您的代码。例如,您可以为您的属性(或方面,它在 AOP 中的调用方式)设置一个自定义属性,该属性将代码注入到属性设置器中,从而将您的对象标记为脏对象。如果您想要一些如何实现这一点的示例,您可以查看他们的 教程.

但要小心 AOP,因为如果使用不当,您可能会很容易地使用它来制造更多您试图解决的问题。

有更多的 AOP 框架,有些使用后编译,有些使用 .Net 中的方法拦截机制,与第一个相比,后者有一些性能缺陷。

不,当您使用自动属性时,您对实现没有任何控制权。最好的选择是使用模板工具、代码片段或创建私有 SetValue<T>(ref T backingField, T value) 封装了 setter 逻辑。

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)来自动创建属性。如果您要创建的属性是数据库表中的列,这将特别有用

我可以推荐使用 企业库 为了这个目的。例如,每当您进入/退出一个方法时,策略应用程序块都会提供基础设施来执行“某事”(某事=您可以自己编写代码)。您可以使用属性来控制行为。以此为提示,详细了解企业库的文档。

有一个可以分配给属性的 DefaultValueAttribute,这主要由设计器工具使用,以便它们可以指示属性何时更改,但是,它可能是描述属性默认值的“简洁”方式,从而能够识别它是否已更改。

您需要使用反射来识别属性更改 - 这实际上不是 除非你做很多,否则很贵!

警告:您将无法判断属性是否已从非默认值更改回默认值。

我想说解决这个问题的最好方法是使用面向方面编程(AOP)。马茨·赫兰德做了一个 在 InfoQ 上写下这个. 。文章有点乱,不过还是可以看懂的。在 .NET 领域有许多不同的产品可以执行 AOP,我推荐 PostSharp。

如果你确实选择属性,我相当肯定你必须这样做 滚动你自己的逻辑 推断出它们的含义以及如何处理它们。无论使用自定义类对象,都必须有一种执行这些属性操作/检查的方法,最好是在实例化时。

否则,您正在考虑使用 Maybe 事件。您仍然需要将事件添加到每个 set 方法中,但这样做的好处是您不必硬编码如何处理每个属性上的脏集,并且可以在一个地方控制要做什么。这至少会引入更多的代码重用。

ContextBound 对象。如果您创建一个扩展上下文绑定对象的类并创建一个 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