Marking code as obsolete/deprecated in C# and Delphi
Posted by jpluimers on 2015/04/07
During any software life cycle, you will want to phase out some code, and most likely want to mark code to be phased out in the future.
So here are two examples on how to do that in C# and in Delphi that just shows the effects of obsoleting/deprecating code.
C#
On the C#/.NET side of things you can mark code to be phased out with the Obsolete attribute that got introduced in C# 1.1 in Visual Studio 2003.
It even allows you to add a string directing you to more appropriate usage patterns.
You can even indicate if this should just be a warning, or that the compiler should issue an error.
Though possible, it is highly unrecommended (is that even proper English?) to use the pragma warning 612/618 disable to circumvent obsolete warnings. Don’t do that!
A small example in C# that uses the .NET framework class library:
Now that IP addresses are not restricted IPv4 any more (which used to be 4 bytes that would fit in a long), but also can be IPv6 (which are 8 groups of 2 bytes totalling 16 bytes – coincidence or not the same size of a GUID), it is not a good idea to use the Address property of an IPAddress instance. So that Address property got obsoleted in .NET 1.1 (it wasn’t in .NET 1.0).
Since the Address property was usually obtained to compare two addresses, now you can use the Equals method or equality (==) operator for that.
ObsoleteConsoleApplication:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Linq; | |
| using System.Net; | |
| using System.Net.Sockets; | |
| namespace ObsoleteConsoleApplication | |
| { | |
| class Program | |
| { | |
| private static IPAddress GetLocalIPAddress() | |
| { | |
| if (!System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable()) | |
| { | |
| return null; | |
| } | |
| IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName()); | |
| return host | |
| .AddressList | |
| .FirstOrDefault(ip => ip.AddressFamily == AddressFamily.InterNetwork); | |
| } | |
| static void Main(string[] args) | |
| { | |
| IPAddress localIpAddress = GetLocalIPAddress(); | |
| long ipv4 = localIpAddress.Address; // Warning 1 'System.Net.IPAddress.Address' is obsolete: 'This property has been deprecated. It is address family dependent. Please use IPAddress.Equals method to perform comparisons. http://go.microsoft.com/fwlink/?linkid=14202' | |
| Console.WriteLine("ipv4={0}", ipv4); | |
| Console.WriteLine("local IP address '{0}'", localIpAddress); | |
| } | |
| /* from the FCL source: | |
| * | |
| [Obsolete("This property has been deprecated. It is address family dependent. Please use IPAddress.Equals method to perform comparisons. http://go.microsoft.com/fwlink/?linkid=14202")] | |
| public long Address { get; set; } | |
| */ | |
| } | |
| } |
Delphi
In Delphi, you use the deprecated directive for this. You can use it to mark code as “obsolete”.
Together with platform , library and experimantal this is one of the hinting directives; the current documentation of Delphi XE6 even allows for adding a string describing the deprecation in more detail, but back in Delphi 6 when deprecated got introduced (and Borland tried the Linux adventure with their Kylix product) you just had the deprecated on its own.
A small Delphi example is about SysUtils.FileAge. It has two overloads, of which one is deprecated.
So the first call will give you a compiler warning:
program DeprecatedFileAge
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| program DeprecatedFileAge; | |
| uses | |
| SysUtils; | |
| {$APPTYPE CONSOLE} | |
| var | |
| ExeName: string; | |
| IntegerAge: Integer; | |
| DateTimeAge: TDateTime; | |
| begin | |
| ExeName := ParamStr(0); | |
| if FileExists(ExeName) then // [Pascal Warning] DeprecatedFileAge.dpr(17): W1000 Symbol 'FileAge' is deprecated | |
| begin | |
| IntegerAge := FileAge(ExeName); | |
| DateTimeAge := FileDateToDateTime(IntegerAge); | |
| Writeln(Format('Age of "%s" is "%s"', [ExeName, DateTimeToStr(DateTimeAge)])); | |
| end; | |
| if FileAge(ExeName, DateTimeAge) then | |
| begin | |
| Writeln(Format('Age of "%s" is "%s"', [ExeName, DateTimeToStr(DateTimeAge)])); | |
| end; | |
| (* | |
| In de SysUtils unit: | |
| { FileAge returns the date-and-time stamp of the specified file. The return | |
| value can be converted to a TDateTime value using the FileDateToDateTime | |
| function. The return value is -1 if the file does not exist. This version | |
| does not support date-and-time stamps prior to 1980 and after 2107. } | |
| function FileAge(const FileName: string): Integer; overload; deprecated; | |
| { FileAge retrieves the date-and-time stamp of the specified file as a | |
| TDateTime. This version supports all valid NTFS date-and-time stamps | |
| and returns a boolean value that indicates whether the specified | |
| file exists. } | |
| {$IFDEF MSWINDOWS} | |
| function FileAge(const FileName: string; out FileDateTime: TDateTime): Boolean; overload; | |
| {$ENDIF} | |
| *) | |
| end. |
–jeroen






smile said
…
{$region ‘Conditional Compilation’}
{$IFDEF CONDITIONALEXPRESSIONS}
{$IF CompilerVersion > 18.5} // Delphi 2007 18.5 VER185
{$DEFINE D2009UP} // Define for Delphi and C++Builder 2009
{$DEFINE DCT_MSG} // Deprecated messages
{$IFEND}
{$ENDIF}
{$endregion}
…
function Connect: Boolean; deprecated {$IFDEF DCT_MSG}’IOracleDOA.ExecuteLogon'{$ENDIF};
Marjan said
In Delphi you can also add a message to the deprecated keyword. Syntax:
[[deprecated(“message”)]]
Example given in the docs :
A(int x, int y) [[deprecated(“use the A(int,double) constructor”)]]{}
will give a :
W8111 Accessing deprecated entity ‘A::A(int,int)’ use the A(int,double) constructor
jpluimers said
Indeed. Besides the example from the C++ documentation you give, this also holds for Delphi and has been introduced in Delphi 2009. Delphi uses different compiler warning numbers than the C++ compiler.
See https://wiert.me/2014/10/01/delphi-hinting-directives-deprecated-experimental-library-and-platform/
Marjan said
Missed that it was the C++ docs. When are the delphi docs ever gonna be rid of the C++ “pollution” :(
jpluimers said
(:
jpluimers said
Delphi XE8 has chm docs. Yay!