这让我最近对我正在开展的一个项目感到震惊。大多数人都熟悉属性递归:
public int Test
{
get { return this.test; }
set { this.Test = value; }
}
private int test;
你不小心在这个setter中放了一个大写字母T,你自己打开了StackoverflowException
。更糟糕的是,如果你没有定义它,通常visual studio会自动纠正套管,使你进入无效状态。
我最近在构造函数中做了类似的事情:
public TestClass(int test)
{
this.Test = Test;
}
不幸的是,在这里你没有得到StackOverflowException,现在你遇到了编程错误。在我的情况下,这个值被传递给一个WebService,而后者使用了一个默认值(不是0),这导致我错过了我错误地分配它的事实。集成测试全部通过,因为该服务没有说
“嘿,你忘记了这个非常重要的领域!”
我可以采取哪些措施来避免这种行为?我一直被建议不要像以下那样定义变量,我个人不喜欢它们,但我想不出任何其他选择:
private int _test;
private int mTest;
修改
我可以想到的下划线或前缀不正常的原因是:
答案 0 :(得分:62)
最好的方法是在这里使用“自动实现的属性”。
public int Test { get; set; }
如果由于某种原因无法使用“自动实现的属性”,请使用_
前缀(我不喜欢)。
如果您也不想使用某些前缀,那么您还有其他选择。您不必手动编写属性代码。让IDE为你做;这样你可以避免粗心的错误。 (我不知道我在原始答案中是如何错过的)
输入
private int test;
选择字段,右键单击Refactor-> Encapsulate Field。 IDE将为您生成属性片段,如下所示。
public int Test
{
get { return test; }
set { test = value; }
}
您无需费心单击上下文菜单。如果您更喜欢键盘,则快捷键为 Ctrl + R + E 。
或者得到一个Resharper,它会立即指出你的愚蠢错误。
答案 1 :(得分:33)
集成测试全部通过
然后他们没有详尽的测试。如果测试没有发现错误,那么你还需要另外一个测试。
这真的是这里唯一的自动化解决方案。编译器不会抱怨,因为代码在结构和语法上都是正确的。它在运行时没有逻辑上正确。
您可以定义命名标准,甚至可以使用StyleCop等工具来尝试执行这些标准。这可能会让你覆盖很多,虽然它不是一个铁定的解决方案,错误仍然可以通过。就个人而言,我同意你的看法,装饰变量名称在代码中是不雅观的。也许在某些情况下这是一个有效的权衡?
最终,自动化测试可以防御这些错误。最简单的是,如果错误通过您的测试并进入生产,那么响应应为:
当然,这只涵盖一个案例,而不是代码中的每个属性定义。但如果发生这种情况很多那么你可能会遇到人员问题,而不是技术问题。团队中有人是邋。的。该问题的解决方案可能不是技术问题。
答案 2 :(得分:6)
使用代码段。
对于由私有字段支持的每个属性,请使用您创建的自定义代码段,而不是从头开始编写它或让IntelliSense完成工作(很差)。
毕竟,这个问题是关于惯例和纪律,而不是语言设计。 C#的区分大小写特性和Visual Studio中完美的代码完成是我们犯这些错误的原因,而不是我们缺乏知识和设计。
这里最好的选择是消除事故发生的可能性,并且正确地编写这些重复性事物的预定义方式是最好的方法。与记住约定和手动强制执行相比,它也更加自动化。
Visual Studio中有一个默认的代码段。键入propfull
并按Tab键,然后指定实例变量名称和属性名称,您就可以了。
答案 3 :(得分:3)
在某些情况下,你无法绕过二传手和吸气鬼。但是如果你遵循Tell,Do not Ask原则,也许你不需要设置者和吸气剂?它基本上说更喜欢让拥有数据的对象完成工作,而不是从数据对象中查询很多其他对象,做出决策,然后将数据写回数据对象。见http://martinfowler.com/bliki/TellDontAsk.html
答案 4 :(得分:2)
你能不能写一个测试来涵盖这个?
int constructorValue = 4;
TestClass test = new TestClass(constructorValue);
Assert.Equals(test.Test, constructorValue);
您可能不想立即编写测试以防止未来的摆动,但您发现了一个错误,为什么不再保护自己呢?
对于记录,如果我需要私有字段来存储pulic getter / setter的值,我总是强调它。这只是一个强调隐私的下划线!
public string Test
{
get { return _test; }
set { _test = value; }
}
private string _test;