26

考虑以下代码:

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?`
    }
}

A并且B几乎完全相同,但是有一个我会错过的错误。

有没有办法在编译时捕获第一个案例?

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

4

7 回答 7

6

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

于 2012-10-26T05:44:51.060 回答
4

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

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

所以编译器不知道这是否是一个错误。当然我会避免这种情况,因为使用这样的代码并不容易(例如,如果你只有一个程序集并且不知道为什么 A 每次都在改变)并且我会避免暴露这样一个属性的显式设置器并喜欢以下内容:

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

public void Reset()
{
    _UniqueID = 0;
}

结论

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

(编辑)避免误导性命名

我以与您相同的方式编写属性和参数。因此,作为一个简单类的外观示例:

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

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

我每周大约 1 次像你一样陷入同样的​​陷阱,所以我从没想过改变命名。但是有一些你可以使用的建议:

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

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

于 2012-10-29T08:37:25.430 回答
4

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

在此处输入图像描述

这些红色指示器之一在右边距中:

在此处输入图像描述

这在状态栏中:

在此处输入图像描述

作为 ReSharper 用户,您很快就会无法忽视它们的组合:)

不过,不会阻止你编译。

于 2012-11-01T13:56:21.137 回答
4

杰伊,

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

  1. 没有办法隐式处理这个问题。.Net 编译器允许递归属性,这是这个问题的核心(就无法“捕获”它而言)。请注意,根据这个问题,这不太可能改变。
  2. 因此,如果您想强制捕获此“错误”,则需要通过 3rd 方工具明确执行此操作。我和许多其他人一样是 ReSharper 粉丝,这使我们能够在必要时突出显示属性递归。同样正如其他人所提到的,使用 FXCop 以及有效的单元测试模式也将帮助您防止出现此类错误。
  3. 命名约定为王。通过提供一个故意“无用”(!)变量和属性命名的示例,您已经准确地强调了为什么我们都应该使用有效的命名约定。您强调的问题已经引起了我们所有人的注意,并且随着代码库的增长而变得更加普遍。

虽然可能不是您想要的答案,但我认为#3 是这里最重要的一点。正确命名项目是唯一最有效的解决方案。不仅如此,人们可能没有奢侈的依赖 ReSharper 和其他此类工具。

为此,我还推荐StyleCop。它可能有点侵入性,但它是帮助开发人员或开发团队遵守一组语法约定的好工具,您会发现这些约定将很快消除诸如您突出显示的错误之类的错误。

快乐编码!

于 2012-11-01T16:57:10.913 回答
2

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

csc /warnaserror C.cs

csc /warnaserror:1717 C.cs

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

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

于 2012-11-02T20:50:02.983 回答
1

无序:

  1. 使用 VB.NET

  2. 单元测试您的代码。

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

  4. 我看到了 FxCop 的建议,并认为使用自省的自定义代码分析规则值得一提。

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

许多 C# 开发人员声明一个与类型名称相同的变量,除了第一个字母小写。这种做法可能是您希望改变的。

于 2012-10-31T05:37:24.820 回答
0

为什么自分配字段this.B = B;是错误的?因为它什么都不做。this.B并且B是完全相同的东西。

为什么自分配财产this.A = A;没有错?因为 of 的含义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;
    }    
}
于 2012-10-29T08:59:26.667 回答