专栏首页walterlv - 吕毅的博客用 AppContext 解决类库的更新兼容问题

用 AppContext 解决类库的更新兼容问题

用 AppContext 解决类库的更新兼容问题

2017-09-30 15:45

还记得微软在 Mitigation: Pointer-based Touch and Stylus Support 中告诉大家如何在 .NET Framework 4.7 中迁移 WPF 的触控到基于 Pointer 消息?记得关键的 <AppContextSwitchOverrides value="Switch.System.Windows.Input.Stylus.EnablePointerSupport=true"/> 这一句吗?

有没有好奇为何这一句话能用来控制微软基础类库中某一块功能的行为呢?阅读本文将了解微软为开发者提供的一套类库更新的兼容性解决方案——AppContext


这是微软自 .NET Framework 4.6 开始为开发者们提供的方案。

比如你打算为你的类库增加了一个功能——指定一个文件夹名称用于存放文件。你写出了这样的代码:

// 1.0 版本的类库
public static class StorageSomeInfo
{
    public static void SetDirectoryName(string directoryName)
    {
        _directory = directoryName ?? throw new ArgumentNullException(nameof(directoryName));
        // 其他逻辑。
    }
}

故事背景

你将类库发布到 NuGet 上,一切运行安好。

直到有一天,某人给 directoryName 传入了空字符串。结果你的文件全部都不再存到指定的文件夹下,而是存到了根目录……这跟你的预期不符啊!

然而,类库发布了这么久,这么多人都下载安装使用了,要是随随便便把代码改成这样,搞不好一大堆小伙伴将面临着崩溃……(谁知道他们有没有依赖于你的 BUG 编程呢?搞不好他们绞尽脑汁发现这样还可以存到根目录呢于是就开开心心地用了呢!)

// 2.0 版本的类库
public static class StorageSomeInfo
{
    public static void SetDirectoryName(string directoryName)
    {
        if (string.IsNullOrWhitespace(directoryName))
            throw new ArgumentException(nameof(directoryName));
        // 其他逻辑。
    }
}

[Obsolete] 是一个好方案,他能够指导开发者一步步迁移他们对 API 的使用。不过:

  1. 如果调用的代码太多了,迁移起来就是个痛苦的差事儿。
  2. 难得取了个好名字,要知道取名字可是编程中最难的事儿之一啊!
  3. 更多的开发者们其实根本没意识到你写出了这个坑,于是凭什么让他们升级 API?!

使用 AppContext

这时候祭出——AppContext

将你的 2.0 代码改成这样:

// 2.0 版本的类库
public static class StorageSomeInfo
{
    public static void SetDirectoryName(string directoryName)
    {
        if (AppContext.TryGetSwitch("Switch.StorageSomeInfo.UseLegacyDirectoryName", out var flag)
            && flag == true)
            // 跑以前的代码
        else
            // 跑新的代码
         
        // 其他逻辑。
    }
}

那么开发者们更新你的类库时,就有可以挽回的方案了:

  1. 如果开发者们没有遇到什么问题,那么恭喜你那位开发者很幸运没有踩到你的坑,你平滑迁移过去了!
  2. 如果开发者们遇到了根目录问题,那么你的更新日志中的指导说明将起作用。

你可以在更新日志中写下说明:

  1. 建议开发者们修改此方法的调用,避免写出错误的代码;
  2. 如果开发者们很难改动这样的代码,可以要求开发者在 app.config 文件中添加以下代码以使用“遗弃的”逻辑。

<configuration> <runtime> <AppContextSwitchOverrides value="Switch.StorageSomeInfo.UseLegacyDirectoryName=true" /> </runtime> </configuration>


更多 AppContext 的信息

开发者们如果有多个开关需要开启或关闭,则使用分号分隔多个开关:

<AppContextSwitchOverrides value="switchName1=value1;switchName2=value2" /> 

开发者们如果不想写配置文件,也可以直接在程序中调用:

AppContext.SetSwitch(string, bool);

当然,甚至可以直接动用注册表:HKLM\SOFTWARE\Microsoft\.NETFramework\AppContext 作为 Key,字符串作为 Value。依然是分号分割的键值对作为注册表项的值来存。如果采用注册表方案,将影响这台计算机上运行的所有程序。

这三种方式的优先级是:

  1. 代码中直接调用的优先级最高;
  2. app.config 中指定的优先级其次;
  3. 在注册表中指定的优先级最低。

一点坑

在从 .NET Framework 4.6 升级到 4.7 后,注册表的方式貌似失效了。参考:FIX: AppContext switch overrides are not applied to applications that run on the .NET Framework 4.7

本文会经常更新,请阅读原文: https://walterlv.com/post/dotnet/2017/09/30/app-context.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 吕毅 (包含链接: https://walterlv.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 (walter.lv@qq.com)

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • (C#)if (this == null)?你在逗我,this 怎么可能为 null!用 IL 编译和反编译看穿一切

    发布于 2018-03-31 00:26 更新于 2018-09...

    walterlv
  • 配置 legacyUnhandledExceptionPolicy 防止后台线程抛出的异常让程序崩溃退出

    发布于 2017-10-16 12:52 更新于 2017-10...

    walterlv
  • WPF 中如何绑定附加属性?XAML 中记得加括号,C# 中记得不能用字符串

    在 XAML 中写绑定是 WPF 学习的必修课,进阶一点的,是用 C# 代码来写绑定。然而一旦绑定的属性是附加属性,好多小伙伴就会开始遇到坑了。

    walterlv
  • 机器学习不是要取代工作,而是重新设计工作

    围绕人工智能和自动化的争论似乎一直都是悲观主义者占主导,他们担心机器人会取代所有的工作,而乐观主义者则不以为然。但麻省理工学院Sloan教授Erik Brynj...

    机器人网
  • 学并发编程,透彻理解这三个核心是关键

    上一篇文章这次走进并发的世界,请不要错过 给大家带了并发编程的开胃菜,接下来我们逐步上正餐,在吃正餐之前,我还要引用那首诗词: 「横看成岭侧成峰,远近高低各不同...

    码农小胖哥
  • 线程概念简介 什么是线程 多线程上篇(七)

    在20世纪 60年代人们提出了进程的概念后,在OS中一直都是以进程作为能拥有资源和独立运行的基本单位的。

    noteless
  • 这3个并发编程的核心,你一定要知道!

    如果你已经工作了,那么你一定听说过或者正在应用敏捷开发模式来交付日常的工作任务,我们就用你熟悉的流程来解释这三个核心问题

    程序员追风
  • 使用dict和set

    Python内置了字典:dict的支持,dict全称dictionary,在其他语言中也称为map,使用键-值(key-value)存储,具有极快的查找速度。-...

    企鹅号小编
  • 论文阅读: RetinaNet

    此篇论文获得了ICCV最佳学生论文奖,指导人是FAIR的He Kaiming大神:

    JNingWei
  • c# 框架学习(nop )总结-------编辑功能

    wfaceboss

扫码关注云+社区

领取腾讯云代金券