如何避免财产recursion

最近,我在一个正在进行的项目中遇到了这个问题。 大多数人都熟悉财产recursion:

public int Test { get { return this.test; } set { this.Test = value; } } private int test; 

你不小心把一个大写的T放在这个setter中,并且你打开了一个StackoverflowException 。 更糟糕的是,如果你没有定义它,通常Visual Studio会自动纠正你的套pipe到无效状态。

最近我在一个构造函数中做了类似的事情:

 public TestClass(int test) { this.Test = Test; } 

不幸的是,在这里你不会得到一个StackOverflowException,现在你有一个编程错误。 在我的情况下,这个值传递给一个WebService,而不是使用默认值(这不是0),这使我错过了我错误地分配它的事实。 整合testing全部通过,因为这个服务没有说

“嘿,你忘了这个真正重要的领域!”

我可以采取哪些措施来避免这种行为? 我一直build议不要像以下那样定义variables,我不喜欢他们个人,但我想不出任何其他select:

 private int _test; private int mTest; 

编辑

下划线或m前缀通常不可取的原因我能想到的是:

  • 可读性
  • 如果您从第三方类inheritance,那么在您混合使用样式时稍微难以滚动浏览成员。

最好的方法是在这里使用“自动实现的属性”。

 public int Test { get; set; } 

如果不能使用“自动实现的属性”出于某种原因使用_前缀(我不喜欢,但)。

如果你也不喜欢使用一些前缀,那么你有其他的select。 您不必手动编写财产代码。 让IDE为你做; 这样你可以避免不小心的错误。 (我不知道我原来的答案是如何遗漏的)

只要input

 private int test; 

select该字段,右键单击重构 – >封装字段。 IDE将为您生成属性片段,如下所示。

 public int Test { get { return test; } set { test = value; } } 

您无需费心点击上下文菜单。 如果你喜欢键盘,快捷键是Ctrl + R + E。

或者得到一个Resharper,它会立即指出你的愚蠢的错误。

整合testing全部通过

然后,他们没有足够的testing。 如果有一个testing未发现的错误,那么你还有另一个testing要写。

这真是这里唯一的自动化解决scheme。 编译器不会抱怨,因为代码在结构和语法上是正确的。 运行时只是在逻辑上不正确。

您可以定义命名标准,甚至可以使用像StyleCop这样的工具来尝试执行这些标准。 这可能会让你覆盖很多,虽然这不是一个铁定的解决scheme,错误仍然可以通过。 就我个人而言,我同意你在代码中装饰variables名字是不好看的。 也许在某些情况下,这是一个有效的权衡?

最终,自动化testing是防御这些types的错误。 最简单的,如果一个错误通过你的testing并进入生产,那么响应应该是:

  1. 写一个testing来重现错误。
  2. 修复错误。
  3. 使用testing来validation修复。

当然,只包含这种情况,并不是代码中的每个属性定义。 但如果这种情况发生了很多,那么你可能会遇到人事问题,而不是技术问题。 队里有人马虎。 解决这个问题可能不是一个技术问题。

使用代码片段。

对于由私人领域支持的每个属性,请使用您创build的自定义代码片段,而不是从头开始编写或让IntelliSense完成这项工作(很差)。

毕竟,这个问题是关于公约和纪律的,而不是语言devise。 C#的区分大小写以及Visual Studio中的完整代码完成是我们犯这些错误的原因,而不是我们缺乏知识和devise的原因。

这里最好的办法就是消除事故发生的可能性,并且正确地写出这些重复的事情是最好的方法。 与记忆约定和手工执行相比,它也更加自动化。

Visual Studio中有一个默认的代码片段。 键入propfull然后点击Tab,然后指定实例variables名称和属性名称,然后就可以开始了。

在某些情况下,你无法绕过制定者和获得者。 但是如果你遵循Tell,Do not Ask的原则,也许你不需要setter和getters? 它基本上说,更喜欢让有数据的对象完成工作,而不是从数据对象中查询很多其他对象,做出决定,然后将数据写回数据对象。 请参阅http://martinfowler.com/bliki/TellDontAsk.html

你不能只是写一个testing来覆盖这个?

 int constructorValue = 4; TestClass test = new TestClass(constructorValue); Assert.Equals(test.Test, constructorValue); 

您可能不想立即编写testing来覆盖未来的抖动,但您已经发现了一个错误,为什么不再保护自己呢?

为了logging,如果我需要私有字段来存储pulic getter / setter的值,我总是强调它。 只是一个下划线,尖叫隐私!

 public string Test { get { return _test; } set { _test = value; } } private string _test;