---
title: "Marking API's as obsolete or as experimental"
description: "Often times your API in your program or library evolves. So you will need a mechanism of telling that a specific API (an interface or just a simple method call) is obsolete and might be not there anymore in the next major version.\n\nAlso it can happen that you have a preview version of a API, which might not be rock-stable and the API-surface might change. How do we indicate that to the user?"
updated: 2022-11-03
tags: ["C#", "API", ".NET"]
canonical: "https://steven-giesel.com/blogPost/1d97ea56-9a32-4067-9919-10b9af5623a6/marking-apis-as-obsolete-or-as-experimental"
---

# Marking API's as obsolete or as experimental

Often times your API in your program or library evolves. So you will need a mechanism for telling that a specific API (an interface or just a simple method call) is obsolete and might be not there anymore in the next major version.

Also, it can happen that you have a preview version of an API, which might not be rock-stable and the API-surface might change. How do we indicate that to the user?

The simple answer: **Attributes**. .NET knows two special ones in this case:
 * `ObsoleteAttribute`
 * `RequiresPreviewFeaturesAttribute`

They are a bit special.

## `ObsoleteAttribute`
The [`ObsoleteAttribute`](https://learn.microsoft.com/en-us/dotnet/api/system.obsoleteattribute?view=net-7.0) is in the Framework since almost the beginning. It marks that the element should not be used anymore. The attribute is special because the compiler knows of it and treats it in a certain way. Here is a quick example of how to use it:
```csharp
OldWarning(); // Generates warning (or error if you enable treat warnings as errors)
OldError(); // Generates errors

[Obsolete($"Take {nameof(New)} instead", false)]
void OldWarning() { }

[Obsolete($"Take {nameof(New)} instead", true)]
void OldError() { }

void New() { }
```

The first argument is a message to a user, which you can use to indicate, which new method he should use instead. The second one is about whether or not the compiler should treat it as a warning (which is the default, if you don't provide that parameter) or even as an error. The compiler tells you the following: "*CS0618: Local function 'OldWarning()' is obsolete: Take New instead*".

So you can make a 3 step approach:
 1. Mark it as warning
 2. Mark it as error
 3. Remove it entirely

By the way the attribute can also be set on a class, property, interface or struct. You are not limited to use it on methods.

## `RequiresPreviewFeaturesAttribute`
The [`RequiresPreviewFeaturesAttribute`](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.versioning.requirespreviewfeaturesattribute?view=net-6.0) is used to indicate that a feature is in a preview state. Feature can mean a simple method or a whole class or interface. The usage is roughly the same:
```csharp
New();

[RequiresPreviewFeatures("API might change")]
void New() { }
```

If you hover over the `New()` call you get the message: "*API might change*". If you try to compile that, you get even an error: "*Program.cs(1, 1): [CA2252] API might change Using 'New' requires opting into preview features. See https://aka.ms/dotnet-warnings/preview-features for more information.*"

The resolve that you have to opt-in into preview features. This is done on project level:
```xml
<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
        <TargetFramework>net7.0</TargetFramework>

        <!-- This will opt in into all preview features -->
        <EnablePreviewFeatures>true</EnablePreviewFeatures>
    </PropertyGroup>
```

Unfortunately it isn't very fine grained. You don't have control over which features you want to use. The (maybe ugly) alternative is using pragmas:
```csharp
#pragma warning disable CA2252
New();
#pragma warning restore CA2252
```

In any way, this is until now (.net 7) the only way of marking an API as a preview. In contrast to the `ObsoleteAttribute`, which is handled by the compiler, the `RequiresPreviewFeaturesAttribute ` is handled via Roslyn-Analyzer.

## Conclusion
I showed you a way of marking your APIs as old so you can delete them gracefully later and I also showed you how to mark them as experimental so your user knows, that the API surface is not stable.