.NET 4.6 で追加された互換性スイッチ

大分間が空いていますが、前回から引き続きで .NET 4.6 について見ています。

dotnet/dotnet46-changes.md at master · Microsoft/dotnet · GitHub
DotNet4.6.md · GitHub
.NET Framework 4.6 におけるランタイムの変更点

互換性スイッチ

というものが新たに追加されました。

その名の通り、(後方) 互換性を保つための機能です。
MS の想定としては「ライブラリを作成する人」と「ライブラリを利用する人」の間で文脈を共有するための機能らしく、ライブラリの新機能のオプトアウトに使って欲しいようです。

まぁ先にコード見ましょうコード。

以下の通り Application プロジェクトと Library プロジェクトを構成します。

f:id:kendik:20150929181912p:plain

で、実装は以下の通りです。

public class LibraryClass
{
    public static double GetPi()
    {
        bool optout;
        if (!AppContext.TryGetSwitch("Switch.Library.DisableNewFeature", out optout))
        {
            optout = false;
        }

        return optout ? 3.14 : 3;
    }
}

 

static void Main(string[] args)
{
    Console.WriteLine(LibraryClass.GetPi());

    AppContext.SetSwitch("Switch.Library.DisableNewFeature", true); // ← New!!

    Console.WriteLine(LibraryClass.GetPi());
}

// 結果
// 3
// 3.14

このように、新しく追加された AppContext クラス を使うことでゆとり教育前の円周率を取得できるようになりました (あ、たまたま最初に思いついただけで、ゆとり教育に対して意見とか変な意図とかはないですよ念のため)。

気をつけるべきこと

まぁでも後方互換に関してはメソッドパラメータやライブラリ独自の設定などでも担保できますね。実際やってるライブラリもあるでしょう。にも関わらず態々こういう機能を出してきたのは

ライブラリの作成者が統一された新機能のオプトアウト メカニズムをユーザーに提供できるようにする

ということらしいです。

なので、スイッチ名 (SetSwitch メソッドの第一引数) にも推奨される形式があります。

  • Switch.namespace.switchname
  • Switch.library.switchname

また、原則として「利用者から明示的にスイッチが指定されない」or「利用者がスイッチを false にした」場合はオプトアウトを提供しない = 最新の機能を利用できるようにすべき、とのこと。

ここらへんの注意点は全部無視しても動くっちゃ動きますが、目的を考えると、利用する際はきちんと意識したいですね。

使いどころ

まぁ MS の言うとおりライブラリ作るときですかねー。それでも普通の人は頻繁には使わなさそうな気がします。互換性維持したらメンテ大変だもんなぁ。
とはいえ、私も一度だけこういう機能が欲しいと思ったことがあるので、まぁ覚えておいて損はないかもですね。ちなみにその時はライブラリ側に新機能用のメソッドを作るという残念対応をしました。あーあ。

余談

冒頭にリンク張ってるドキュメント中に

この機能は、既存の機能が変更される場合に特に重要です。これに対し、新しい機能に関する暗黙的なオプトインは既に実装されています。

という文言があるんですがこれどういう意味か誰か教えてください。。。
AppContext クラスのようなオプトインできる機能があるってことですかね。利用するバージョン上げるなよって話でオプトインも何もないと思うんですが。うーん。