如何避免财产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并进入生产,那么响应应该是:
- 写一个testing来重现错误。
- 修复错误。
- 使用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;