如何将代码标记为“不再使用”

14
我经常遇到这样的情况,我想劝其他开发人员不要继续使用一个方法或类。例如,假设我有两个库方法“A”和“B”,其中“A”是完成某个任务的“旧”方式,“B”是完成该任务的“新”方式。在许多情况下,A和B之间存在足够明显的差异使得重构使用A的代码以开始使用B变得不容易(例如需要传递额外状态)。由于A在使用它的情况下可以正常工作,因此我不想优先考虑重构。然而,我确实希望给我的同事开发人员一个视觉指示,告诉他们不应在新代码中使用A。
因此,理想情况下,我希望得到引用了 ObsoleteAttribute 成员时获得的删除线效果,但不出现相应的编译器警告/错误(因为打开它会从所有不打算很快解决的旧版本A的使用中发出数百个错误)。这样,如果开发人员编写了一个使用A的新行,则立即会注意到删除线并修复代码以使用B。
是否有办法在Visual Studio(2012)中获得这种功能?
编辑:
- 已经有几篇评论指出“无法区分新旧代码”。我同意。但这不是我所要求的,所以让我澄清一下:相反,我希望获得代码“过时”的视觉表示(例如删除线),而不会出现相应的编译器警告或错误。这样,在阅读旧代码或编写新代码的过程中,开发人员将立即获得某些内容已过时的视觉指示。即使在.NET中无法本地支持此功能,也可能有一个用于此目的的VS扩展?有一些评论认为“你既不能警告,也不能不警告”。我认为我在上面已经解释了使用案例,但我会再试一次。我们有一组核心库在各种解决方案中广泛使用。有时,我会更新其中的一个库以提供执行某些任务的新API。为了保持向后兼容性,在许多情况下,我不能简单地删除旧的执行该任务的方式,因为大量现有的代码依赖于使用旧的API集,并且不能轻易地重构为使用新的API。此外,没有迫切的理由这样做;它只会增加现有代码中的BUG风险。然而,我希望有一种方式可以直观地提醒开发人员,某些API应该避免使用,而选择其他API。这很困难,因为开发人员往往通过阅读已完成相同任务的现有代码来学习如何完成某项任务。这使得新API很难传播,因为旧的根深蒂固的API被大量现有代码所引用。 ObsoleteAttribute 通过编译器警告实现了这一点,但是那些警告只会从旧API的数百个现有用途中创建大量噪音。这就是为什么我喜欢删除线:它是非常直观的,但它只会干扰开发人员在阅读或编写使用过时API的代码时。以下是一些更改示例,我想标记旧API:
  • 我们引入了一个新的运行SQL查询的API,这个API比以前的API更简洁、更灵活。很难彻底删除旧的API,因为它有许多奇怪的行为可能被依赖。然而,对于未来的开发,我希望推动人们使用新的API。
  • 我们有两组内部单元测试辅助API。旧的API完全可用,但它依赖于继承,而且不太灵活。新的API使用属性构建,更灵活。数百个旧测试仍然使用旧的API,但我希望推动编写新测试的作者使用新的API。
  • 我们的核心库中存在一些陈旧的随机遗留代码,这些代码并不真正适合使用,但此时将其删除却很困难。我希望限制向这些类型和方法添加新引用,这样随着现有依赖于它们的代码因为正常更替而消失,可能会变得划算将其删除。
  • 另外,我认为这个问题的答案很好地描述了为什么即使不建议在新代码中使用某些内容,也可能不会将其标记为过时。

  • 有几个评论/回答仅仅指出了ObsoleteAttribute的存在。请注意,这个问题的文字一直都提到了这个属性。


  • 这可能会有所帮助:https://dev59.com/oW435IYBdhLWcg3wrSLN#5275270 - Federico Berasategui
    2
    所以你想让 ObsoleteAttribute 只在新代码中起作用,我不认为编译器能够做到这一点,我的意思是:在编译时所有代码的年龄都是相同的! - ichramm
    2
    可能是重复的问题:如何将方法标记为过时/弃用? - abelenky
    3
    评论/答案中有很多不必要的讽刺。我们都可以认同,过时的属性不能很好地处理这种用例,并且可能没有什么.NET/Visual Studio可以完美地满足问题中详细描述的需求。然而,这并不意味着答案应该只是“你无法做到”。至少,答案应该解释为什么不建议这么做。"Pragma"的解决方法似乎也可以很有用。虽然不是理想的,但却很有用。在我看来,StackOverflow是关于实用性,而不一定是理想的。 - Mark Hildreth
    @ChaseMedallion 这个问题最终怎么解决了?你有没有找到比过时的更好的东西? - crthompson
    显示剩余5条评论
    4个回答

    11
    Obsolete属性添加到您的方法中,将在智能感知中给出删除线。
    [ObsoleteAttribute("This property is obsolete. Use NewProperty instead.", false)] 
    public static string OldProperty
    { get { return "The old property value."; } }
    

    要禁用警告,请在属性之前添加以下内容:

    #pragma warning disable 612, 618
    

    并重新启用:

    #pragma warning restore 612, 618
    

    正如这里所述,将忽略放在项目文件中而不是代码中将是一种非常干净的解决方案。

    <WarningsNotAsErrors>618</WarningsNotAsErrors>
    

    编辑:另外,请查看@JonHanna有关使用EditorBrowsable属性的答案。

    正如其他人指出的那样,实际上会抛出两个带有过时属性的警告。

    编辑:

    #pragma warning disable 612, 618
    [Obsolete]
    #pragma warning restore 612, 618
    public class test1
    {...
    

    当你尝试使用test1时,你会得到:

    enter image description here

    请注意,当您键入var test = new test1()时,没有删除线。
    但是test1 test = new test1()将显示删除线。

    我也收到了。可能是因为楼主甚至不想要一个警告。当然,这没有什么意义,所以... - Ed S.
    @EdS。我同意。喜欢您的不屈不挠:) +1 - crthompson
    @paqogomez:那么,即使您通过csproj文件禁用了过时的警告,VS也会显示删除线吗? - ChaseMedallion
    @ChaseMedallion 如果你禁用警告,它仍然会执行删除线。我会尝试发布一个例子。 - crthompson

    8

    所以您想要一个警告,但又不想出现任何警告?

    主要问题在于,没有任何东西在编译时区分“老代码(我们还没意识到问题的)”和“新代码(不应该再使用旧习惯)”,它们都是代码。

    唯一能做的是使用ObsoleteAttribute,然后在当前使用中使用 #pragma warning disable 612, 618。像往常一样,#pragma warning 绝不能存在没有注释的情况:

    #pragma warning 612, 618 //This block of code uses BadOldMethod(), code review planned
    /* ... code here */
    #pragma warning restore 612, 618
    

    当然,如果有足够的理由停止使用某个功能,那么应该尽早进行审核。

    编辑:糟糕,我忘记了612和618。你可以将属性设置为引发619而不是618,但无法禁用它(设置它的一个主要原因是有时候这样更合适)。

    另外一种阻碍可能来自于将成员标记为[EditorBrowsable(EditorBrowsableState.Never)]。由于方法在智能感知中根本不会显示出来,而新方法会显示出来,这会鼓励人们使用新方法(只要库作为库而不是解决方案中的项目或同一项目中的类被引用)。


    1
    关于EditorBrowsable属性的优秀想法 +1 - crthompson

    6

    Use ObsoleteAttribute.

    [ObsoleteAttribute("This method is obsolete. Call NewMethod instead.", false)] 
    public string SomeObsoleteMethod()
    {
       // ...
    }
    

    最后一个参数(IsError)如果设置为true,将会发出编译错误,否则会给出警告。您可以使用#pragma 612, 618来禁用警告。

    编辑:

    好吧,我让步了。您想要的解决方案似乎是:

    /// <summary>
    /// Please don't use
    /// </summary>
    public string SomeObsoleteMethod()
    {
       // ...
    }
    

    没有任何编译器支持。

    他说他甚至不想在他的问题中得到警告,但我认为这是无法避免的。 - Magus
    4
    @Magus:是的,标记某个东西为已弃用(过时)却没有发出警告有点傻。 - Ed S.
    3
    @EdS.:为什么防止项目中出现数百个不必要的警告是愚蠢的? - Tim Schmelter
    @TimSchmelter:它们并不是不必要的...你想告诉用户不要使用那个方法,对吧?那么这就是你要做的。仅通过智能感知禁用它是愚蠢的。使用#pragma显式地禁用它,但至少要这样做。 - Ed S.
    2
    @EdS.:但他已经提到:“由于打开它会从所有旧的A使用中发出数百个错误,而我们不打算在短期内解决这些问题。”我认为这很清晰合理。 - Tim Schmelter
    显示剩余4条评论

    3

    我认为你应该使用ObsoleteAttribute,确保你使用#pragma(参见这里的示例)在现有代码中禁用它。

    随着时间的推移,你会修复代码。


    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接