14

I often end up in a situation where I want to discourage other developers from continuing to use a method or class. For example, let's say I have two library methods "A" and "B" where "A" is the "old" way of doing some task and "B" is the "new" way of doing that task. In many cases, A and B are sufficiently different to make refactoring code using A to start using B non-trivial (e. g. requires flowing through of additional state). Since A works in the cases where it's used, I don't want to prioritize the refactor. I do, however, want to give my fellow developers a visual indication that A is not to be used in new code.

Thus, I'd ideally like the strike-through you get when referencing a member with the ObsoleteAttribute WITHOUT the associated compiler warning/error (since turning that on would emit hundreds of errors from all the old uses of A that we don't plan to address any time soon). That way, if a developer writes a new line of code with A, he or she will immediately notice the strike-through and fix the code to use B.

Is there any way to get such functionality in VisualStudio (2012)?

EDIT:

  • There have been several comments to the effect of "there's no way to distinguish between new and old code". I agree. However, that's not what I'm asking for, so let me clarify: instead, what I want is a visual representation of code being "out of date" (e. g. strikethrough) without the corresponding compiler warning or error. That way, developers in the process of reading old code or writing new code will get an immediate visual indication that something is out of date. Even if this isn't supported natively in .NET, maybe there is a VS extension out there for this purpose?

  • There have been several comments to the effect of "you can't both have a warning and not have a warning". I thought I explained the use case above, but I'll give it another try. We have a set of core libraries which are used heavily throughout the various solutions that comprise our code base. Sometimes, I make an update to one of these libraries which provides a new, better API for performing some task. To maintain backwards compatibility, I can't just remove the old way of doing that task (in many cases), since tons of existing code relies on using the old set of APIs and can't be trivially refactored to use the new one. Furthermore, there's no pressing reason to do so; it would just risk introducing bugs into existing code. However, I'd like some way of visually alerting developers to the fact that certain APIs should be avoided in favor of other ones. This is difficult, since developers tend to learn how to accomplish some task by reading existing code that accomplishes the same task. That makes new APIs hard to spread, since the old entrenched APIs are referenced by so much existing code. The ObsoleteAttribute achieves this via compiler warnings, but those warnings will just create tons of noise from the hundreds of existing uses of the old APIs. That's why I like the strikethrough: it's something that is very visual and yet it will only intrude on a developer when he or she is reading or writing code that uses an out of date API. Here are some examples of changes where I wanted to mark an old API:

    • We introduced a new API for running SQL queries that is less verbose, less quirky, and more flexible than what we had previously. It's hard to outright remove the old API because it has so many quirky behaviors that might be relied on. However, I want to push people towards the new API for future development.
    • We have two internal sets of unit test helper APIs. The older one is perfectly functional, but it depends on inheritance and is not very flexible. The newer one is built using attributes and is more flexible. Hundreds of old tests still run using the old API, but I want to push writers of new tests to use the new API.
    • Our core libraries have some old random legacy code that doesn't really fit but would be difficult to remove at this point. I'd like to curtail the adding of new references to these types and methods. That way, it may become cost effective to remove them at some point as the existing code that depends on them disappears due to normal churn.
  • As a further note, I think the answer to this question does a good job of describing why you might not mark something obsolete even though you wouldn't recommend using it in new code.

  • There are several comments/answers simply calling out the existence of the ObsoleteAttribute. Please note that the text of this question has always referenced that attribute.

Community
  • 1
  • 1
ChaseMedallion
  • 20,860
  • 17
  • 88
  • 152
  • [this](http://stackoverflow.com/a/5275270/643085) might help – Federico Berasategui Jan 14 '14 at 23:00
  • 2
    So you want `ObsoleteAttribute` to work only with new code, I don't think the compiler can do that, I mean: at compilation time all code has the same age! – ichramm Jan 14 '14 at 23:01
  • Im sure it could do it with version control or local diffs. It probably doesn't though – Millie Smith Jan 14 '14 at 23:04
  • 2
    possible duplicate of [How do I mark a method as Obsolete/Deprecated?](http://stackoverflow.com/questions/1759352/how-do-i-mark-a-method-as-obsolete-deprecated) – abelenky Jan 14 '14 at 23:06
  • "I want a warning... but with no warnings"? – Ed S. Jan 14 '14 at 23:09
  • 3
    I think there's a lot of snark in the comments/answers that are unwarranted. We can all agree that the obsolete attribute does not easily handle this use case well, and there's probably nothing that .NET/Visual Studio can do to perfectly meet the exact need detailed in the question. However, that doesn't mean that the answer should just be "you can't do that". An answer should be, at the very least, WHY it doesn't make sense to do it. The "pragma" workaround seems like it could be useful as well. Not ideal, but useful. And AFAIC, StackOverflow is about being useful, not necessarily ideal. – Mark Hildreth Jan 14 '14 at 23:21
  • @MarkHildreth: No one said "you can't do that", we said "mark it obsolete and add a pragma to silence it if needed". Using a deprecated function _should be_ a warning. Compiler support is good. If there is a good reason to disable that then you can do so explicitly instead of "silently" via intellisense (which you can't do practically anyway). – Ed S. Jan 14 '14 at 23:45
  • @abelenky: the question you linked to is basically looking for the ObsoleteAttribute, and that's the accepted answer. My question called out that I didn't want to use the ObsoleteAttribute. Why do you think this might be a duplicate? – ChaseMedallion Jan 15 '14 at 18:06
  • @ChaseMedallion How did things settle on this issue? Did you find something better than obsolete? – crthompson Mar 11 '14 at 18:53
  • @paqogomez: nope. As far as I can tell Obsolete + some amount of warning disabling is the best thing available. – ChaseMedallion Mar 12 '14 at 03:20

4 Answers4

11

Adding the Obsolete attribute to your method will give the strikethrough in intellisense.

[ObsoleteAttribute("This property is obsolete. Use NewProperty instead.", false)] 
public static string OldProperty
{ get { return "The old property value."; } }

To disable the warnings add this before the attribute:

#pragma warning disable 612, 618

And to reenable:

#pragma warning restore 612, 618

As noted here, putting a ignore in your project file instead of in your code would be a very clean solution.

<WarningsNotAsErrors>618</WarningsNotAsErrors>

EDIT: Also, check out @JonHanna's answer about using the EditorBrowsable attribute.

As others have noted, there are actually 2 warnings that are thrown with the obsolete attribute.

EDIT:

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

When you try to use test1 you will get:

enter image description here

Note that when you type var test = new test1() the strikethrough does not occur.

But test1 test = new test1() will show the strikethrough.

Community
  • 1
  • 1
crthompson
  • 15,653
  • 6
  • 58
  • 80
8

So you want a warning, but without any warnings?

The main problem here, is there's nothing that upon compilation distinguishes "old code, before we thought better of it" from "new code, that shouldn't use the old habits"; it's all just code.

About the only thing you could do is to use the ObsoleteAttribute and then use #pragma warning disable 612, 618 on the current uses. As always, #pragma warning should never exist without a comment:

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

Of course, if there's a good reason to stop using it, there's a good reason to make that review sooner, rather than later.

Edit: Oops, I forgot about 612 as well as 618. You can set the attribute to raise 619 instead of 618, but that can't be disabled (one of the main reasons for setting it, is that that sometimes suits).

A further discouragement can come from marking the member as [EditorBrowsable(EditorBrowsableState.Never)]. The fact that the method won't show up in intellisense at all, while the new one will, would encourage people toward the new one (as long as the library is referenced as a library rather than as a project within the solution, or a class within the same project).

Jon Hanna
  • 110,372
  • 10
  • 146
  • 251
6

Use ObsoleteAttribute.

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

The last argument (IsError) will emit a compilation error if set to true, otherwise a warning will be given. You can disable the warnings by using #pragma 612, 618

EDIT:

Ok, fine, I relent. The solution you want appears to be:

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

No compiler support at all.

Ed S.
  • 122,712
  • 22
  • 185
  • 265
  • He says he doesn't even want a warning in his question, but I don't think there's any way around that. – Magus Jan 14 '14 at 23:03
  • 4
    @Magus: Yeah... marking something as deprecated (obsolete) without emitting a warning is just kind of silly... – Ed S. Jan 14 '14 at 23:04
  • 3
    @EdS.: why is it silly to prevent hundreds of unnecessary warning in your project? – Tim Schmelter Jan 14 '14 at 23:06
  • @TimSchmelter: They're not unnecessary... you want to tell the user to *not* use that method, right? Well, that's how you do it. Doing so through intellisense only is silly. Disable it with a pragma, but at least do so explicitly. – Ed S. Jan 14 '14 at 23:07
  • 2
    @EdS.: But he has mentioned: _"since turning that on would emit hundreds of errors from all the old uses of A that we don't plan to address any time soon"_. Imho that's clear and reasonable. – Tim Schmelter Jan 14 '14 at 23:08
  • If you want to disable that warning, try `#pragma warning disable [###]` for the proper warning. – abelenky Jan 14 '14 at 23:08
  • @TimSchmelter: ...then you don't deprecate it. What are you more interested in; having meaningful warnings or hiding them so that you feel better? The issue still exists either way. Like I/we said, you can disable it with a pragma, but at least then the issue is not hidden. – Ed S. Jan 14 '14 at 23:14
  • I'm not sure whether changing the documentation of the method that way is brilliant or horrible. I sort of feel like both upvoting and downvoting that. – Jon Hanna Jan 14 '14 at 23:18
  • @JonHanna: Well... in reality I would probably leave the description as well as add the message... but in (real?) reality I would just mark it as obsolete. – Ed S. Jan 14 '14 at 23:43
3

Personally I think that you should use ObsoleteAttribute, making sure that you use #pragma (see here for examples) to disable it where needed in the existing code.

In time you fix the code.

Community
  • 1
  • 1
Preet Sangha
  • 64,563
  • 18
  • 145
  • 216