Question

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.

Was it helpful?

Solution

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.

OTHER TIPS

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).

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.

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top