C# の Obsolete 属性で非推奨を示す

ライブラリやプロジェクトが成長すると、古いメソッドやクラスを新しい設計に置き換えたくなる。しかし、いきなり削除すると既存のコードが壊れてしまう。Obsolete 属性は「この要素は非推奨です」とコンパイラに伝え、利用者に移行を促すための仕組みだ。

基本的な使い方

Obsolete 属性をメソッドに付けると、そのメソッドを呼び出した箇所でコンパイラが警告を出す。

using System;

public class Calculator
{
    [Obsolete]
    public int Add(int a, int b)
    {
        return a + b;
    }

    public int Sum(params int[] numbers)
    {
        int total = 0;
        foreach (var n in numbers) total += n;
        return total;
    }
}

Add を呼び出すと「‘Calculator.Add(int, int)’ is obsolete」という警告が表示される。プログラムは動くが、開発者に対して「別の方法を使ってほしい」というシグナルになる。

メッセージを付ける

引数なしだと何に移行すればいいかわからない。第 1 引数に文字列を渡すことで、代替手段を具体的に案内できる。

[Obsolete("Add は非推奨です。代わりに Sum を使ってください。")]
public int Add(int a, int b)
{
    return a + b;
}

警告メッセージにこの文字列が含まれるため、呼び出し側の開発者はどこに移行すればよいか一目でわかる。非推奨にする際は、代替手段を必ず明記するのが親切な設計といえる。

警告からエラーに変える

第 2 引数に true を渡すと、警告ではなくコンパイルエラーになる。

警告(デフォルト)

コンパイルは通るが警告が出る。移行期間中に使う。利用者は引き続き古いコードをビルドできる。

エラー(true 指定)

コンパイル自体が失敗する。移行期間が終わり、強制的に切り替えさせたいときに使う。

[Obsolete("Add は廃止されました。Sum を使ってください。", true)]
public int Add(int a, int b)
{
    return a + b;
}

段階的な移行戦略として、最初は警告で周知し、十分な期間を置いてからエラーに切り替えるという運用がよく行われる。

付与できる対象

Obsolete 属性はメソッドだけでなく、クラス、構造体、列挙型、プロパティ、フィールド、イベント、デリゲートなど幅広い要素に付けられる。

[Obsolete("UserData は非推奨です。UserProfile を使ってください。")]
public class UserData
{
    public string Name { get; set; }
}

public class UserProfile
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

クラス全体を非推奨にした場合、そのクラスをインスタンス化したり継承したりするコードすべてで警告またはエラーが発生する。

非推奨にする判断基準

どのタイミングで Obsolete を付けるべきかは、プロジェクトの規模や利用者の数によって変わる。

設計上の問題や命名の改善点を発見

新しい API を実装して十分にテスト

旧 API に Obsolete 属性を付けて移行を周知

十分な移行期間の後、エラーに昇格または削除

公開ライブラリの場合は、セマンティックバージョニングに従い、警告の追加はマイナーバージョン、削除はメジャーバージョンで行うのが一般的だ。社内プロジェクトであっても、いきなり削除するのではなく Obsolete を挟むことで、チームメンバーへの影響を最小限に抑えられる。

IDE との連携

Visual Studio や Rider などの IDE は Obsolete 属性を認識し、呼び出し箇所に取り消し線を表示する。コードを書いている最中にリアルタイムで非推奨であることがわかるため、ドキュメントを読みに行かなくても気づける。コンパイラ警告と IDE の視覚的フィードバックの両方が機能することで、非推奨 API の使用を効果的に減らせるわけだ。