Obsolete属性は廃止予定・非推奨となったクラスやメソッドなどに適用する属性で、機能の利用者に対して、機能が廃止予定・非推奨である旨をコンパイラの警告・エラーによって通知することができます。 Obsolete属性による通知はコンパイラによってサポートされるため、機能の利用者はドキュメントの参照なしに機能が古くなった(obsolete=時代遅れ、廃れた)ことを知ることができます。 Obsolete属性による通知は、Javaにおける@Deprecatedアノテーションなどに相当する機能と言えます。

Obsolete属性を用いることで、API互換性は維持しつつ、バージョンアップによって廃止予定になった機能の通知や、あるいはより洗練された実装への移行を利用者に対して促すことができます。

§1 Obsolete属性の効用

§1.1 クラスライブラリの利用者側

.NET Frameworkのクラスライブラリやサードパーティ製クラスライブラリの利用者側では、Obsolete属性の存在によってライブラリのクラスやメソッドが廃止予定あるいは非推奨であることを知ることができます。 Obsolete属性が付与されたクラス・メソッドを呼びだそうとしている場合、コンパイラは自動的にObsolete属性の存在を検知し、警告あるいはエラーとして利用者に通知します。

例えば、ファイル名に使用できない文字のリストを取得しようとしてPath.InvalidPathCharsフィールドを参照した場合、コンパイラは次のような警告を通知します。

Obsoleteなメンバを呼び出そうとしているコード
using System;
using System.IO;

class Sample {
  static void Main()
  {
    var filename = "foo*bar?.txt";

    // ファイル名に使用できない文字をアンダーバーに置き換える
    foreach (var c in Path.InvalidPathChars) {
      filename = filename.Replace(c, '_');
    }

    Console.WriteLine(filename);
  }
}
コンパイラが出力する警告メッセージ
test.cs(10,23): warning CS0618: 'System.IO.Path.InvalidPathChars' は古い形式です: 'Please use GetInvalidPathChars or GetInvalidFileNameChars instead.'

このように、ライブラリの利用者はコンパイラから通知される警告によって機能が廃止予定・非推奨であることを知ることができます。 また、警告として通知されるメッセージに代替機能についての情報が含まれていれば、それも得ることができます。 Obsolete属性による警告がない場合、事前にドキュメント等を参照していなければ機能が廃止予定であるか、非推奨となっているかどうかを把握することはできませんが、Obsolete属性が付与されていればコンパイラによる通知によってそれを知ることができます。


また、上記の例における警告メッセージでは、Path.InvalidPathCharsの代わりとしてPath.GetInvalidFileNameCharsメソッドを用いることが提示されているため、利用者はこれに従うことで非推奨となっている機能を使用しないコードに書き換えることができます。

提示された代替メソッドを用いるように書き換えたコード
using System;
using System.IO;

class Sample {
  static void Main()
  {
    var filename = "foo*bar?.txt";

    // ファイル名に使用できない文字をアンダーバーに置き換える
    // (非推奨なPath.InvalidPathCharsの代わりにPath.GetInvalidFileNameChars()を用いる)
    foreach (var c in Path.GetInvalidFileNameChars()) {
      filename = filename.Replace(c, '_');
    }

    Console.WriteLine(filename);
  }
}

このように廃止予定・非推奨となっていることを知らずに機能を利用しようとしていた場合でも、Obsolete属性によってそれをコンパイル時までに知ることができ、推奨される代替機能へ移行することができます。

ファイル名・パス名に使用できない文字に関して詳しくはランタイム・システム・プラットフォームの情報 §.ファイル・ディレクトリの区切り文字・無効な文字を参照してください。


Obsolete属性は、IDEによるコード解析機能が使えない場合に、メンバの参照元を検索する用途でも使うことができます。 例えば、次のようにメソッドにObsolete属性をつけることで、そのメソッドを呼び出している個所を警告として表示させることができます。

Obsolete属性の警告を利用してメソッドを呼び出している個所を検索する
using System;

class Sample {
  [Obsolete("メソッドを使用している個所")]
  static void Test()
  {
  }

  static void Main()
  {
    Test();
    // test.cs(11,5): warning CS0618: 'Sample.Test()' は古い形式です: 'メソッドを使用している個所'
  }
}

ユーザー定義の警告・エラーを表示したい場合は、#warningディレクティブ#errorディレクティブを用いることができます。

§1.2 クラスライブラリの提供者側

クラスライブラリの提供者側では、バージョンアップに際して既存の機能を廃止したり、非推奨としたい場合にObsolete属性を用いることができます。 クラスやメソッドに対してObsolete属性を付与することによって、それが廃止予定・非推奨であることを利用者側に通知することができます。

Obsolete属性を使って機能が廃止予定・非推奨であることを利用者に通知する
/* クラスライブラリのコード */
using System;

namespace ClassLibrary {
  public static class StringUtils {
    // 文字列strに含まれる部分文字列substrの数を返すメソッド
    [Obsolete] // <-- Obsolete属性を付与することで廃止予定であることを通知する
    public static int Count(string str, string substr)
    {
      /* 例示のため実装は省略 */
      return 0;
    }
  }
}

このライブラリを利用する側では、このようにObsolete属性が付与されたクラスやメソッドを呼びだそうとした場合、次のようにコンパイラが警告を発します。

Obsolete属性が付与されたメソッドを呼びだそうとすると警告となる
/* ライブラリ利用者のコード */
using System;
using ClassLibrary;

class Sample {
  static void Main()
  {
    string text = "foobarbazfoobarbaz";

    // ライブラリのメソッドを使って文字列textに含まれる"foo"の数を計上したい
    Console.WriteLine(StringUtils.Count(text, "foo"));
  }
}
コンパイラが出力する警告
test.cs(23,23): warning CS0612: 'ClassLibrary.StringUtils.Count(string, string)' は古い形式です。

Obsolete属性では、引数messageで警告として出力する文字列を指定することもできるため、単なる廃止予定の通知だけでなく、廃止予定とする理由や、代替となる機能の存在を同時に通知することができます。

Obsolete属性を使って旧式化の通知と代替機能への移行を提案する
/* クラスライブラリのコード */
using System;

namespace ClassLibrary {
  public static class EnumUtils {
    // 文字列strから対応するEnum値への変換を試みるメソッド
    [Obsolete(".NET Framework 4以降ではSystem.Enum.TryParse()が提供されています。 System.Enum.TryParse()を使ってください。")]
    public static bool TryParse<TEnum>(string str, out TEnum result) where TEnum : struct
    {
      /* 例示のため実装は省略 */
      result = default(TEnum);
      return false;
    }
  }
}
Obsolete属性のメッセージから代替機能の存在を知ることができる
/* ライブラリ利用者のコード */
using System;
using ClassLibrary;

class Sample {
  static void Main()
  {
    var str = "Sunday";

    DayOfWeek d;

    // ここで警告が出力される
    // warning CS0618: 'ClassLibrary.EnumUtils.TryParse<TEnum>(string, out TEnum)' は古い形式です: '.NET Framework 4以降ではSystem.Enum.TryParse()が提供されています。 System.Enum.TryParse()を使ってください。'
    if (EnumUtils.TryParse(str, out d))
      Console.WriteLine(d);

    // この警告メッセージに従って、利用者は可能であれば代替機能を使ったコードに書き換えることができる
    if (Enum.TryParse(str, out d))
      Console.WriteLine(d);
  }
}

また、Obsolete属性の引数errortrueを指定すれば、Obsoleteとなったメンバの使用を警告ではなくエラーとして通知させるようにすることができます。 利用者側では、このようなObsolete属性が付与されたメンバを呼び出そうとするとコンパイルエラーとなり、一切使用することができなくなります。 機能や実装に問題があり、機能へのアクセスや利用を一切禁止したいような場合には、Obsolete属性を使って呼び出しをコンパイルエラーとすることができます。

Obsolete属性を用いて機能へのアクセスをエラー扱いにする
/* クラスライブラリのコード */
using System;

namespace ClassLibrary {
  // POPを使ってメールサーバーにアクセスするクライアント
  public class PopClient {
    // APOPによるログインを試行するメソッド
    [Obsolete(error: true, message: "APOPによるログインには脆弱性が指摘されています。 使用しないでください。 (詳細: http://www.ipa.go.jp/security/vuln/200704_APOP.html)")]
    public void LoginApop(string user, string pass)
    {
      /* 例示のため実装は省略 */
    }
  }
}
Obsolete属性によって機能のアクセスがコンパイルエラーとなる
/* ライブラリ利用者のコード */
using System;
using ClassLibrary;

class Sample {
  static void Main()
  {
    var c = new PopClient();

    // この呼び出しはエラーとなり、コンパイルに失敗する
    // error CS0619: 'ClassLibrary.PopClient.LoginApop(string, string)' は古い形式です: 'APOPによるログインには脆弱性が指摘されています。 使用しないでください。 (詳細: http://www.ipa.go.jp/security/vuln/200704_APOP.html)'
    c.LoginApop("user", "pass");
  }
}

廃止予定ではなく、廃止済みであることを通知したい場合にも、エラーとすることによって利用者に通知できます。

Obsolete属性を用いて機能が廃止済みであることを通知する
/* クラスライブラリのコード */
using System;

namespace ClassLibrary {
  // POPを使ってメールサーバーにアクセスするクライアント
  public class PopClient {
    // APOPによるログインを試行するメソッド
    [Obsolete(error: true, message: "APOPによるログインには脆弱性が指摘されたため、廃止しました。 代わりにPopClient.LoginSaslMD5()などを使用してください。")]
    public void LoginApop(string user, string pass)
    {
      throw new NotSupportedException();
    }

    // SASL MD5を使ったログインを試行するメソッド
    public void LoginSaslMD5(string user, string pass)
    {
      /* 例示のため実装は省略 */
    }
  }
}

このほかにも、ライブラリ実装の都合あるいは経緯上、ライブラリ外に公開せざるを得ない(publicな)クラスやメソッドが存在する場合にもObsolete属性を用いることができます。 例えば過去のバージョンで公開していた機能を安全な形に隠蔽するようにした場合や、デザイナや外部ツールなどから参照されるような利用者が直接使用しない機能などが考えられます。

ドキュメント等に記載されないようなクラスやメソッドの場合でも、それがpublicであれば入力候補等で表示されてしまいます。 このようなメンバにObsolete属性を付与しておくことによって、利用者が誤って使用してしまうことや、意図的に使用した場合の結果が保証できないことを通知することができます。

Obsolete属性を使って「非公式な」メンバの参照を警告する
using System;

namespace ClassLibrary {
  public static class Infrastructure {
    // 実装上の都合でpublicとせざるを得ないメソッド
    [Obsolete("ライブラリの初期化に必要なメソッドです。 ライブラリ外から呼び出した場合は現在の状態が変更されるため呼び出さないでください。")]
    public static void Initialize()
    {
    }

    // 実装上の都合でpublicとせざるを得ないプロパティ
    [Obsolete("ライブラリの状態取得に必要なプロパティです。 このプロパティの情報を前提としたコードを記述しないでください。")]
    public static bool IsInitialize {
      get { return true; }
    }
  }
}

.NET Frameworkのクラスライブラリにおいてもこのようなメンバが存在します。 例えばWebClient.AllowReadStreamBufferingプロパティなどはObsolete属性が付与されていて、ユーザーが直接使用することを想定としたものではないことが通知されるようになっています。

メンバの存在をデバッガやデザイナから見えなくする目的には、DebuggerHidden属性DebuggerNonUserCode属性などを用いることができます。 詳しくはデバッグ操作と属性を参照してください、



§2 .NET Frameworkクラスライブラリの非推奨な型・メンバ

.NET Frameworkのクラスライブラリでは、既にUri.MakeRelativeメソッドPath.InvalidPathCharsフィールドなどにObsolete属性が適用され、非推奨となっています。 このほかにも、ドキュメントの以下のページにて非推奨となった型・メンバの一覧が掲載されています。

§3 Obsolete属性を適用できる個所

Obsolete属性は、次のようにクラス・構造体・インターフェイスなどのすべての型、およびメソッド・プロパティ・イベント・フィールドなどのメンバに対して適用することができます。 また、publicではない型・メンバにも適用することができます。 アセンブリ全体をObsoleteにすることはできません。

様々な要素にObsolete属性を付与する
using System;

// アセンブリ全体には適用できない
//[assembly: Obsolete]

namespace ClassLibrary {
  [Obsolete]
  public struct S { }

  [Obsolete]
  public interface I {}

  [Obsolete]
  public class C {

    [Obsolete]
    void Method()
    {
    }

    [Obsolete]
    bool Property {
      get; set;
    }

    [Obsolete]
    event EventHandler Event;

    [Obsolete]
    int Field;
  }
}

型全体に対してObsolete属性を適用した場合、その型のすべてのメンバにObsolete属性が適用された状態と同じになります。 型全体をObsoleteにして、特定のメンバのみを非Obsoleteにするといったことはできません。

Obsoleteな型のメンバを呼び出すと警告となる
using System;

// クラス全体をObsoleteにする
[Obsolete]
static class Utils {
  // 必然的にこのメソッドもObsoleteとなる
  public static void UtilMethod()
  {
  }
}

class Sample {
  static void Main()
  {
    // Obsoleteな型のメンバを参照しようとすると警告となる
    // warning CS0612: 'Utils' は古い形式です。
    Utils.UtilMethod();
  }
}

§4 機能提供開始から廃止までとObsolete属性

ここでは、クラスライブラリで一度提供を開始したメソッドをObsoleteとし、最終的に廃止するまでをリリース毎に考えていきます。 機能の廃止や置き換えに関するリリースポリシーの一例としてご覧ください。

まず、最初のリリースでは以下のようにメソッドを提供したとします。

クラスライブラリ・バージョン1
using System;

[assembly: System.Reflection.AssemblyVersion("1.0.*")]

namespace ClassLibrary {
  public static class StringUtils {
    /// <summary>文字列の並びを逆転した結果を返します。</summary>
    /// <returns><paramref name="str"/>の文字の並びを逆転した<see cref="System.String"/>を返します。</returns>
    public static string Reverse(string str)
    {
      /* 例示のため実装は省略 */
      return string.Empty;
    }
  }
}

実装に問題がある、より洗練された実装を提供するなどの理由により、今後のリリースではこのメソッドの利用を推奨しないことになったとします。 これに従い、メソッドにObsolete属性を追加することによって利用者にその旨を通知します。 同時に、代替となる新しいメソッドも用意します。

クラスライブラリ・バージョン2
[assembly: System.Reflection.AssemblyVersion("2.0.*")]

using System;

namespace ClassLibrary {
  public static class StringUtils {
    /// <summary>文字列の並びを逆転した結果を返します。</summary>
    /// <remarks>このメソッドはサロゲートペアを含む文字列を正しく処理できません。</remarks>
    /// <returns><paramref name="str"/>の文字の並びを逆転した<see cref="System.String"/>を返します。</returns>
    [Obsolete("このメソッドは推奨されません。 文字列がサロゲートペアを含む場合はCodePointWiseReverse()を使用してください。")]
    public static string Reverse(string str)
    {
      /* 例示のため実装は省略 */
      return string.Empty;
    }

    /// <summary>文字列の並びを逆転した結果を返します。</summary>
    /// <returns><paramref name="str"/>の文字の並びを逆転した<see cref="System.String"/>を返します。</returns>
    /// <remarks>このメソッドはサロゲートペアを含む文字列でも正しく処理します。</remarks>
    public static string CodePointWiseReverse(string str)
    {
      /* 例示のため実装は省略 */
      return string.Empty;
    }
  }
}

このとき、旧式メソッドと動作が変わらない代替メソッドを提供できる場合や、動作が変わっても問題ないと判断する場合は、旧式メソッドから代替メソッドを呼び出すようにして機能を完全に置き換えてしまうこともできます。

クラスライブラリ・バージョン2
using System;

[assembly: System.Reflection.AssemblyVersion("2.0.*")]

namespace ClassLibrary {
  public static class StringUtils {
    /// <summary>文字列の並びを逆転した結果を返します。</summary>
    /// <returns><paramref name="str"/>の文字の並びを逆転した<see cref="System.String"/>を返します。</returns>
    [Obsolete("このメソッドは廃止予定です。 CodePointWiseReverse()を使用してください。")]
    public static string Reverse(string str)
    {
      // 代替メソッドを使用する実装にする
      return CodePointWiseReverse(str);
    }

    /// <summary>文字列の並びを逆転した結果を返します。</summary>
    /// <returns><paramref name="str"/>の文字の並びを逆転した<see cref="System.String"/>を返します。</returns>
    /// <remarks>このメソッドはサロゲートペアを含む文字列でも正しく処理します。</remarks>
    public static string CodePointWiseReverse(string str)
    {
      /* 例示のため実装は省略 */
      return string.Empty;
    }
  }
}

次のリリースでは、これまでに廃止予定としたメソッドを廃止することになったとします。 これに従いObsolete属性のメッセージを変更し、またこれまで警告としていたメソッドの利用を、error = trueを追加してエラーとして扱うように変更します。

クラスライブラリ・バージョン3
using System;

[assembly: System.Reflection.AssemblyVersion("3.0.*")]

namespace ClassLibrary {
  public static class StringUtils {
    /// <summary>文字列の並びを逆転した結果を返します。</summary>
    /// <remarks>このメソッドは廃止されました。 CodePointWiseReverse()を使用してください。</remarks>
    /// <returns><paramref name="str"/>の文字の並びを逆転した<see cref="System.String"/>を返します。</returns>
    [Obsolete(error: true, message: "このメソッドは廃止されました。 CodePointWiseReverse()を使用してください。")]
    public static string Reverse(string str)
    {
      /* 例示のため実装は省略 */
      return string.Empty;
    }

    /// <summary>文字列の並びを逆転した結果を返します。</summary>
    /// <returns><paramref name="str"/>の文字の並びを逆転した<see cref="System.String"/>を返します。</returns>
    /// <remarks>このメソッドはサロゲートペアを含む文字列でも正しく処理します。</remarks>
    public static string CodePointWiseReverse(string str)
    {
      /* 例示のため実装は省略 */
      return string.Empty;
    }
  }
}

この時点で、利用者は旧式のメソッドを使うことができなくなり、代替メソッドを使用しなければならなくなります。

Obsolete属性による警告・エラーは、コンパイル時にのみ発せられます。 従って、ライブラリを参照するコンパイル済みのコードがある場合、ライブラリ側でObsolete属性が警告からエラーに変わったとしても、コンパイル済みコードの実行には影響しません。 再コンパイルする時点で初めてエラーとして通知されます。

実行可能ファイルを再コンパイルせず、コンパイル済みのライブラリだけを置き換えてバージョンアップするようなシナリオの場合、Obsolete属性のerrorパラメータがfalseからtrueに変わっても、引き続き旧式のメソッドが呼び出されることになります。

旧式メソッドの廃止に伴い、実装も削除すると判断した場合は、次のように例外NotSupportedExceptionをスローするようにすることもできます。

クラスライブラリ・バージョン3
using System;

[assembly: System.Reflection.AssemblyVersion("3.0.*")]

namespace ClassLibrary {
  public static class StringUtils {
    /// <summary>文字列の並びを逆転した結果を返します。</summary>
    /// <remarks>このメソッドは廃止されました。 CodePointWiseReverse()を使用してください。</remarks>
    /// <exception cref="NotSupportedException">このメソッドを呼び出した場合にスローされます。</exception>
    [Obsolete(error: true, message: "このメソッドは廃止されました。 CodePointWiseReverse()を使用してください。")]
    public static string Reverse(string str)
    {
      throw new NotSupportedException("このメソッドは廃止されました。 CodePointWiseReverse()を使用してください。");
    }

    /// <summary>文字列の並びを逆転した結果を返します。</summary>
    /// <returns><paramref name="str"/>の文字の並びを逆転した<see cref="System.String"/>を返します。</returns>
    /// <remarks>このメソッドはサロゲートペアを含む文字列でも正しく処理します。</remarks>
    public static string CodePointWiseReverse(string str)
    {
      /* 例示のため実装は省略 */
      return string.Empty;
    }
  }
}

errorパラメータをtrueにした時点で、新たにコンパイルするコードではエラーとなり、利用できない状態になります。 しかし、コンパイル済みのコードからは依然として呼び出し自体は可能であるため、そういった呼び出しも禁止したい場合はこのように例外をスローするようにします。

実装されていない旨を強調するために、NotSupportedExceptionではなくNotImplementedExceptionをスローすることも考えられます。 ただ、NotImplementedExceptionでは今後実装される可能性のニュアンスを含むため、完全に廃止された機能の場合はどちらの例外がより妥当かどうかは判断が分かれます。

.NET Frameworkでは、ObsoleteExceptionやDeprecatedExceptionといったようなこの状況に適した例外クラスは用意されていません。 十分な必要性があるなら、NotSupportedExceptionあるいはNotImplementedExceptionを継承してこのような例外クラスを作成し、スローするということも考えられます。


ここまでの時点では、機能自体は廃止したものの、クラスライブラリのAPI互換性は維持されています。

クラスライブラリのAPI互換性を破壊するようなリリースを行っても問題ないと判断する場合は、次のように完全にメソッド自体を削除した上でリリースすることもできます。

クラスライブラリ・バージョン4
using System;

[assembly: System.Reflection.AssemblyVersion("4.0.*")]

namespace ClassLibrary {
  public static class StringUtils {
    /*
     * 廃止したメソッドを完全に削除する(API互換性は失われる)
     *
    [Obsolete(error: true, message: "このメソッドは廃止されました。 CodePointWiseReverse()を使用してください。")]
    public static string Reverse(string str)
    {
      throw new NotSupportedException("このメソッドは廃止されました。 CodePointWiseReverse()を使用してください。");
    }
    */

    /// <summary>文字列の並びを逆転した結果を返します。</summary>
    /// <returns><paramref name="str"/>の文字の並びを逆転した<see cref="System.String"/>を返します。</returns>
    /// <remarks>このメソッドはサロゲートペアを含む文字列でも正しく処理します。</remarks>
    public static string CodePointWiseReverse(string str)
    {
      /* 例示のため実装は省略 */
      return string.Empty;
    }
  }
}

ここまでの例でライブラリのバージョンを明記するために用いた属性AssemblyVersionについてはアセンブリのバージョン情報を取得するなどを参照してください。

§5 Obsolete属性とXMLドキュメントコメント

C#やVB.NETでは、XMLドキュメントコメントによってメソッドの機能・動作・引数と戻り値の説明などを記述することができます。 しかし、Javadocにおける@deprecatedタグのような廃止予定・非推奨となった旨を記述する要素、例えば<obsolete><deprecated>のような要素は定義されていません。 そのため<summary>要素や<remarks>要素として記述する必要があります。

なお、Javadoc コメントと等価な XML ドキュメントおよび<deprecated> (JavaScript)によれば、J#では<obsolete>要素、JavaScriptでは<deprecated>要素が定義されています。 C#やVB.NETでもこういった要素を使った記述自体は行えますが、ドキュメントによって定義されていない要素のため、ビューアーやドキュメントジェネレータが対応していない限り、適切に表示されるとは限りません。

この他、XMLドキュメントコメントで用いることができる要素と意味についての詳細はXMLドキュメントコメントを用いたドキュメントの作成 §.XMLドキュメントコメントの要素を参照してください。