在 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 協議,意味著允許任何人任何組織和企業任意處置,包括使用,復制,修改,合并,發表,分發,再授權,或者銷售,在倉庫里面包含了完全的構建邏輯,只需要本地的網路足夠好(因為需要下載一堆構建工具),即可進行本地構建
博客園博客只做備份,博客發布就不再更新,如果想看最新博客,請到 https://blog.lindexi.com/

本作品采用知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議進行許可,歡迎轉載、使用、重新發布,但務必保留文章署名[林德熙](http://blog.csdn.net/lindexi_gd)(包含鏈接:http://blog.csdn.net/lindexi_gd ),不得用于商業目的,基于本文修改后的作品務必以相同的許可發布,如有任何疑問,請與我[聯系](mailto:[email protected]),
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/447154.html
標籤:WPF
