• dotnet 读 WPF 源代码笔记 为什么加上 BooleanBoxes 类


    在 WPF 框架,为什么需要定义一个 BooleanBoxes 类。为什么在 D3DImage 的 Callback 方法里面,传入的是 object 对象,却能被转换为布尔。本文将告诉大家为什么需要这样设计

    大家都知道,在 dotnet 里面,如果将一个结构体通过 object 的方式传输,将需要进行装箱。而装箱将会创建一个新的对象。在 WPF 这个框架里面,有很多逻辑,例如消息,都是非常快速在调用的。如果每次调用,例如传输布尔值,由于需要进入很多框架逻辑,而让参数只能使用 object 类型,那么每次都使用结构体将需要多次的装箱,从而创建大量的对象

    创建大量的对象将会让界面逻辑需要不断进行内存回收,自然性能就降低了

    那为什么不设计一个泛形呢?因为代码将不好写,同时由于泛形类型的静态属性将不相同,从而再次让逻辑更加复杂。而且对于大多数逻辑来说,确实传输的只是引用对象,传输结构体还是一个比较少的业务。在 WPF 框架,为了解决此问题,于是就创建了 KnownBoxes 系列类型。包括 NullableBooleanBoxes 和 BooleanBoxes 类型。这两个类型将预先将布尔装箱,当成 object 对象。接下来,所有需要对布尔装箱的逻辑,都将使用 BooleanBoxes 的对象代替

    以下代码是 BooleanBoxes 的逻辑

        internal static class BooleanBoxes
        {
            internal static object TrueBox = true;
            internal static object FalseBox = false;
    
            internal static object Box(bool value)
            {
                if (value)
                {
                    return TrueBox;
                }
                else
                {
                    return FalseBox;
                }
            }
        }
    

    可以看到 BooleanBoxes 的 TrueBox 和 FalseBox 属性都是由布尔装箱创建的。为什么创建的方法是需要使用布尔装箱,而不是随便拿两个对象?原因是如此方便重新转换为布尔值

    使用 BooleanBoxes 的性能如何?请看 https://github.com/dotnet/runtime/issues/7079#issuecomment-264500921

    Method Mean StdDev Median Scaled
    BoolUncachedBoxing 7.3923 ns 0.0391 ns 7.3866 ns 1.00
    BoolCachedBoxing 4.5859 ns 0.0310 ns 4.5954 ns 0.62

    那为什么在 dotnet 里面,不默认加上此优化呢?原因是如文档,每次在 dotnet 的装箱,都是生成新的对象。没错,新的对象。因此如果做此优化,将修改行为

    那这和 D3DImage 的 Callback 方法里面,有什么关系呢?其实在此方法里面,调用到 SetIsFrontBufferAvailable 方法,在此方法里面进行了一次强转,于是我开始阅读代码,认为强转会炸,先来看看此方法做了什么

            private object SetIsFrontBufferAvailable(object isAvailableVersionPair)
            {
                Pair pair = (Pair)isAvailableVersionPair;
                uint version = (uint)pair.Second;
    
                if (version == _version)
                {
                    bool isFrontBufferAvailable = (bool)pair.First;
                    SetValue(IsFrontBufferAvailablePropertyKey, isFrontBufferAvailable);
                }
    
                // ...just because DispatcherOperationCallback requires returning an object
                return null;
            }
    

    此方法的参数能拿到一个 Pair 类型的对象,然而此对象的两个值都是 object 类型,需要进行一次转换。然而在 Callback 方法里面,代码如下

            private void Callback(bool isFrontBufferAvailable, uint version)
            {
                Dispatcher.BeginInvoke(
                    DispatcherPriority.Normal,
                    new DispatcherOperationCallback(SetIsFrontBufferAvailable),
                    new Pair(BooleanBoxes.Box(isFrontBufferAvailable), version)
                    );
            }
    

    可以看到在传入的参数,拿到的 Pair 的第一个参数,是用 BooleanBoxes 创建的。然而在 SetIsFrontBufferAvailable 方法里面,将此参数进行了强转。相当于 (bool) BooleanBoxes.Box(isFrontBufferAvailable) 的代码。我开始看到 BooleanBoxes 的 Box 返回的是一个 object 对象,以为对 object 对象进行强转肯定会炸。实际上这是不会炸的,转换是符合预期的

    那为什么一个 object 对象,在 SetIsFrontBufferAvailable 能被转换为布尔呢?这就是 BooleanBoxes 的属性都是由布尔装箱创建的原因。因为本来是通过布尔装箱创建的,也因此能被转换为布尔值

    以上就是 WPF 为什么加上 BooleanBoxes 类的原因,以及在 D3DImage 里,使用布尔强转一个 object 可以符合预期

    更多逻辑,还请阅读 WPF 源代码

    当前的 WPF 在 https://github.com/dotnet/wpf 完全开源,使用友好的 MIT 协议,意味着允许任何人任何组织和企业任意处置,包括使用,复制,修改,合并,发表,分发,再授权,或者销售。在仓库里面包含了完全的构建逻辑,只需要本地的网络足够好(因为需要下载一堆构建工具),即可进行本地构建

  • 相关阅读:
    win10磁盘碎片整理
    Windows10系统一键结束所有运行程序
    win10关闭后台应用程序进程的方法
    第一章 进化的分子基础
    xshell分隔符及全路径提示
    GEOquery
    Gviz
    用R包来下载sra数据
    Analyzing Microarray Data with R
    IRanges package
  • 原文地址:https://www.cnblogs.com/lindexi/p/16042466.html
Copyright © 2020-2023  润新知