Arno# - The cutting edge of developer waffle

Some random thoughts on software development

System.Obsolete: Controlling class and member obsolescence

What is it?

    [System.Obsolete(<optional description>, <optional error flag>)]
    <class or member definition>...

System.Obsolete is a simple attribute that can be used to mark entire classes, or one or more members of a class, as obsolete. When thus marked, the compiler will either throw a warning or error if you then use that obsolete item within your code. Whether a warning or error is given is determined by a parameter to the attribute.

Which C# version supports it?

Version 2.0 and above.

Why use it?

As your software grows and evolves, so early aspects of it may become superseded by newer, better, ways of doing things. Traditionally, you then had two ways of signaling this to a customer:

  1. Add a comment to the affect that the class or member was depreciated and that could they please stop using it.
  2. Remove the obsolete item from a release so that it couldn’t be used.

Option 1 tended to be ineffective. It takes effort to rewrite code that uses depreciated functionality. Much easier for the customer to just ignore your advice.

Option 2 tended to be very effective … at getting customers annoyed. They upgrade to your latest version and now code that once worked, fails to compile.

System.Obsolete breaks this undesirable dichotomy apart and offers a very nice third option. Now depreciated functionality can cause a compiler warning. The customer then gets to either ignore that warning, or upgrade to the new functionality to remove it. Unlike the warning being in the docs though, this warning is there, in his face, every time he compiles. This is much more difficult to ignore, especially if the customer follows best practice and treats compiler warnings as errors.

Further, remember there is the option to cause the compiler to throw an error, rather than a warning, when you use depreciated functionality. If you were to just remove it, the compiler would throw a confusing “not found” error. Now you can cause it to throw an error that explains why it’s depreciated, and how the customer can best get their code working again.

How to use it

As previously mentioned, that attribute can be applied either to a whole class, or to a member within a class. I’ll cover classes first, going into detail of the various options, then will briefly explain how the same principles can be applied to class members.

Example 1: obsolete class gives vague warning
The following code will yield a simple “‘Org.DavidArno.ExampleClass’ is obsolete” warning:

namespace Org.DavidArno
{
    [System.Obsolete()]
    public class ExampleClass
    {
    }

    public class CustomerClass
    {
        private ExampleClass ec;
    }
}

Example 2: obsolete class gives a helpful warning
The following two code snippets will yield the warning
“‘Org.DavidArno.ExampleClass’ is obsolete ‘Please use ExampleClass2 instead’”

namespace Org.DavidArno
{
    [System.Obsolete("Please use ExampleClass2 instead")]
    public class ExampleClass
    {
    }

    public class CustomerClass
    {
        private ExampleClass ec;
    }
}

namespace Org.DavidArno
{
    [System.Obsolete("Please use ExampleClass2 instead", false)]
    public class ExampleClass
    {
    }

    public class CustomerClass
    {
        private ExampleClass ec;
    }
}

In the latter case, the optional error flag is set false to indicate that a warning, rather than an error, is required. This is strictly speaking an unnecessary example as this is the default behaviour if the flag isn’t specified, but I’ve added it for completeness.

Example 3: depreciated class gives a helpful error
The following code snippet will yield the error
“‘Org.DavidArno.ExampleClass’ is obsolete ‘Please use ExampleClass2 instead’”

namespace Org.DavidArno
{
    [System.Obsolete("Please use ExampleClass2 instead", true)]
    public class ExampleClass
    {
    }

    public class CustomerClass
    {
        private ExampleClass ec;
    }
}

Here the optional error flag is set true. In this case, trying to use ExampleClass will cause a compiler error.

Example 4: obsolete class members
In the above examples, the whole class was marked as obsolete. It is possible to mark a class member as obsolete instead. The same parameters apply, so one can have a terse or verbose message and it can either cause a compiler warning or error.

namespace Org.DavidArno
{
    public class ExampleClass
    {
        [System.Obsolete("Please use Method2 instead", true)]
        public void Method1()
        {
        }

        public void Method2()
        {
        }
    }

    public class CustomerClass
    {
        public CustomerClass()
        {
            ExampleClass ec = new ExampleClass();
            ec.Method2();
            ec.Method1();
        }
    }
}

In this case, we get a “‘Org.DavidArno.ExampleClass.Method1()’ is obsolete: ‘Please use Method2 instead’ error against line 21. Notice that lines 19-20 do not give an error as only Method1() is obsolete.

1 Comment so far

  1. [...] much the .NET 4 framework might grow by, Brad and his colleagues could try making heavy use of the System.Obsolete class to reduce the numbers. Now that really would make it easier to build .NET [...]

Leave a reply

Close