6

I have a class with a member that I need to keep for legacy code and I need to mark it as obsolete so that new code doesn't use it (without getting a warning).

Let's say the class looks like this:

class MyClass
{
    [Obsolete]
    private string _old = "...";

    [Obsolete]
    public string Old
    {
        get { return _old; }
    }
}

I'm declaring that the member field _old is obsolete to make sure that new code inside the class do not use that field.

I'm also declaring that the property Old is obsolete to make sure that code outside of the class do not use the property.

When I compile this I get a warning in the property getter saying that _old is obsolete. I thought that the compiler would silently ignore this since the property itself is obsolete.

Am I missing something or do I need to add #pragma warning disable/restore for obsolete member fields everywhere they're used (even though the method/property itself is marked as obsolete)?


The reason that "I thought that the compiler would silently ignore this" is because it seems to do so for obsolete classes:

[Obsolete]
public class MyObsoleteClass
{
    public string DoSomething()
    {
        // No warning here, since the class itself is obsolete
        return new MyClass().Old;
    }
}

As @Heinzi answered: this seems to be due to a bug in Visual Studio. I've filed a report on connect:

https://connect.microsoft.com/VisualStudio/feedback/details/1146809


It turns out that the bug in Visual Studio is not just limited to accessing an obsolete field from a property.

Accessing an obsolete property from an obsolete method should not yield a warning:

public class Class2
{
    [Obsolete]
    public string Property { get; set; }

    [Obsolete]
    public void Method()
    {
        this.Property = "value"; // <-- Incorrect warning reported
    }
}

Neither should doing so from another class:

public class Class3
{
    [Obsolete]
    public string Property { get; set; }
}

public class Class4
{
    [Obsolete]
    public string Method()
    {
        return new Class3().Property; // <-- Incorrect warning reported
    }
}

Interestingly, it works in the following class and when adding this class the other warnings (from Class4 and Class2) will magically disappear.

public class Class5
{
    [Obsolete]
    public void Method()
    {
        // No warning reported here, which is good.
        // This magically makes the other warnings disappear too!
        new Class2().Method();
    }
}
Mårten Wikström
  • 11,074
  • 5
  • 47
  • 87
  • 1
    Why not refactor the (internal) code to use the right internal field? Then you have the warning just once (for the property) which is the Obsolete-attribute is designed for - external use. – MakePeaceGreatAgain Feb 24 '15 at 13:18
  • I need to keep the field as it is. Legacy code need to keep using it. However, that code will be marked obsolete as well. New code shall use the new stuff, but old code shall be able to still exist and use the old stuff. – Mårten Wikström Feb 24 '15 at 13:20
  • "*I thought that the compiler would silently ignore this since the property itself is obsolete.*" What made you think so? Is there something in the documentation that indicates this? – Jeroen Vannevel Feb 24 '15 at 13:22
  • Are you sure the warning is still there after you recompile the project? On my PC (VS 2012), the warning disappears after recompiling. .NET Fiddle seems to agree: https://dotnetfiddle.net/CVFN5a (try removing [Obsolete] from the property and you will get the warning, add it, and the warning disappears). – Heinzi Feb 24 '15 at 13:23
  • @Heinzi: It sometimes disappear but as soon as I make changes to the code the warning appear again. Perhaps it is just the "background compiler" that generate this warning. If so, it's very annoying... – Mårten Wikström Feb 24 '15 at 13:25
  • @MårtenWikström: Then it seems to be a bug in Visual Studio. Recompile the project and check the "Output" tab: The warning should be there when [Obsolete] is removed, and it should be gone when [Obsolete] is re-added. Everything else is Visual Studio magic rather than the compiler's fault. – Heinzi Feb 24 '15 at 13:26
  • What you describe is true in Xamarin Studio 5.7.1 and mono 3.12.0; there are no obsolete warnings when compiling your code. Removing the [Obsolete] attribute on your method will generate a warning about accessing the obsolete field. This is also how I remembered Visual Studio to work, but I am unable to find any documentation about it. – sisve Feb 24 '15 at 13:43

2 Answers2

3

Your code is fine, and your understanding of how the Obsolete attribute should work is correct: If you look at the "Output" tab after compilation, you will note that the compiler does not output a warning for your case (but will output a warning if you remove the Obsolete attribute from your property, as expected).

You are right, though, that Visual Studio sometimes displays a warning after making arbitrary changes to the code. This seems to be a bug in Visual Studio. If you can still reproduce it with the most current version, I would suggest that you file a bug report on http://connect.microsoft.com.

Heinzi
  • 167,459
  • 57
  • 363
  • 519
0

This would be a clever feature, but I don't see any indication in the documentation that it should work this way. On the other hand I would not use the Obsolate attribute on a private member (if the class is not extremly huge), but I would refactor it instead. I your case I would write this:

class MyClass
{
    [Obsolete]
    public string Old
    {
        get; private set;
    }
}

And then you only need to change the usages of _old to Old and the problem is solved.

Gábor Angyal
  • 2,225
  • 17
  • 27
  • I need to keep the private member. Both for legacy code within the class and for serialization contract. – Mårten Wikström Feb 24 '15 at 13:36
  • Well for the legacy code this wouldn't be a too dangerous change. (If you are not explicitly forbidden to make changes to it.) I am not familiar with the serialization contract, so I sadly can't comment on that ... – Gábor Angyal Feb 24 '15 at 13:46