是否有自动方式来捕捉财产自我分配?

时间:2012-10-26 04:40:22

标签: c#

请考虑以下代码:

class C
{
    public int A { get; set; }
    public int B;

    public C(int a, int b)
    {
        this.A = A;    // Oops, bug! Should be `this.A = a`. No warning
        this.B = B;    // Oops, bug! Should be `this.B = b`. `warning CS1717: Assignment made to same variable; did you mean to assign something else?`
    }
}

AB几乎完全相同,但有一个我会错过的错误。

有没有办法在编译时抓住第一个案例?

编辑:部分答案&评论想向我解释一下属性和字段不是一回事。我已经知道了。他们解释了为什么编译器在这里没有警告;我明白了。但是我写了一个bug,我不喜欢写错误。所以我的问题是“我怎样才能确保我永远不会再写这个错误了?

7 个答案:

答案 0 :(得分:6)

您可以使用FxCop等工具并使用VisitAssignmentStatement编写自定义规则:
一些例子:
Example1
Example2

答案 1 :(得分:4)

你说A = AB = B是一样的,但事实并非如此!您可以在propery的getter和setter中进行更改,以便A = A可以更改变量,如下例所示:

public Int32 A
{
    get { return _A++; }
    set { _A = value; }
}

所以编译器不知道它是不是错误。当然,我会避免这种情况,因为它不是那么容易使用这样的代码(如果你只是有一个程序集,并且不知道为什么A每次都在改变),我会避免暴露这样一个明确的setter财产,喜欢下面的东西。

public UInt32 UniqueID { get { _UniqueID++; } }

public void Reset()
{
    _UniqueID = 0;
}

结论

编译时错误在这里没有任何意义,因为编译器不知道属性中发生了什么(记住:属性只是两种方法的简化,set_MyProperty和get_MyProperty ) ,如果属性发生变化(通过虚拟化),行为也可能会发生变化。

(编辑)避免误导性的namings

我以与您相同的方式编写属性和参数。例如,一个简单的类看起来如何:

public class MyClass
{
    public Int32 Sample { get; private set; }

    public MyClass(Int32 sample)
    {
        Sample = sample;
    }
}

我每周都会和你一样陷入同样的​​陷阱〜大约1次,所以我从没想过要改变这些陷阱。但是你可以使用一些建议:

  • 使用p(参数)作为前缀,但这是我不推荐的,因为它使代码不可读恕我直言。
  • 使用value作为后缀,这对我来说似乎没问题。因此,sample代替sampleValue而不是Sample(属性名称),并且应该更容易检测是否使用属性名称而不是参数1
  • 使用_作为前缀。我不会使用它,因为我已经使用_作为成员的前缀,以便能够快速访问它们并使智能感知看起来很奇怪恕我直言。

我认为这完全取决于您的个人或公司编码风格,但我个人会使用Value作为后缀。

答案 2 :(得分:4)

这不是铸铁,但如果您安装了ReSharper并将其“未使用参数”检查设置为“错误”,并进一步启用了解决方案范围分析,您会在代码窗口中看到:

enter image description here

右边缘的其中一个红色指标:

enter image description here

这在状态栏中显示:

enter image description here

它们共同构成一个组合,作为ReSharper用户,您很快就会无法忽视:)

不会阻止你编译。

答案 3 :(得分:4)

周杰伦,

一个很好的问题。我相信大多数相关的要点都已在各种回复中涵盖,但总结一下:

  1. 没有办法隐含地处理这个问题。 .Net编译器允许递归属性,这是这个问题的核心(就无法“捕获”它而言)。请注意,根据this question,这不太可能发生变化。
  2. 因此,如果您想强制捕获此“错误”,则需要通过第三方工具明确地执行此操作。我和许多其他人一样是ReSharper粉丝,这使我们可以在必要时强调属性递归。正如其他人所提到的,使用FXCop和有效的单元测试模式也可以帮助您防止出现这些错误。
  3. 命名惯例是王道。通过提供一个有意图“无用”(!)变量和属性命名的示例,您已经突出显示了为什么我们都应该使用有效的命名约定。你强调的问题是让我们全部陷入困境的问题,并随着代码库的增长而变得越来越普遍。
  4. 虽然可能不是你追求的答案,但我认为#3是最重要的一点。正确命名项目是最有效的解决方案。不仅如此,人们可能没有依赖ReSharper和其他此类工具的奢侈品。

    为此,我还建议StyleCop。它可能有点侵入性,但它是一个很好的工具,可以帮助开发人员或开发团队遵守一套语法约定,你会发现这些约定会很快消除你突出显示的错误。< / p>

    快乐的编码!

答案 4 :(得分:2)

除了上述所有答案之外,您还可以在项目属性中,在“构建”选项卡下,启用“将警告视为错误”,仅输入特定警告。如果您使用命令行编译器:

csc / warnaserror C.cs

csc / warnaserror:1717 C.cs

来自文档:http://msdn.microsoft.com/en-us/library/406xhdz3.aspx

这将使您的构建在所有警告或您指定的警告上失败。

答案 5 :(得分:1)

无序:

  1. 使用VB.NET

  2. 单元测试您的代码。

  3. 使用ReSharper并接受提示“Qualifer'this'is redundant” - 然后查找警告:Assignment made to same variable; did you mean to assign something else?

  4. 我看到了FxCop的建议,并认为Custom Code Analysis Rules using Introspection值得一提。

  5. 使用更好的变量名来识别参数与成员。这个提示当然不是高科技。我经常将变量与常量,数字或条件语句中函数的返回值进行比较。虽然读取起来稍微困难,但我习惯于在==运算符的左侧放置不能用作l值的操作数,忘记在==运算符中键入第二个等号将导致(非常明显的)编译器错误(五秒钟修复),而不是以后必须追踪逻辑错误(五分钟修复)。我觉得这一点与非常轻微的语法错误有关,这个错误只会让你陷入困境。

  6. 许多C#开发人员声明一个变量与类型名称相同,但小写的第一个字母除外。这种做法可能是你想要改变的。

答案 6 :(得分:0)

为什么字段this.B = B;的自我分配错误?因为它什么也没做。 this.BB完全相同。

为什么属性this.A = A;的自我分配没有错?因为A的含义取决于它所代表的=运营商的哪一方。考虑编译器如何看待此代码:

set_A(get_A());

这是两种不同方法的调用。如果你打电话给Foo(Bar());,你认为这是一个警告吗?也没有编译器。在getter中更改后备存储并不好,但要考虑属性,计算读数的数量,或进行一些日志记录,或者放置任何其他逻辑。为什么编译器会警告你呢?

public int A
{
    get 
    {
       _log.Debug("Property A accessed by some user");
       _readingsCount++;
       // your logic goes here
       return _a;
    }    
}