首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

《Effective C#》精要:減少裝箱與拆箱,提升效能

     編輯:關於C#

.NET 類型分為「值類型」與「參考類型」兩大類。值類型資料配置在堆疊,參考類型資料配置在堆積。當需將值類型放入堆積(如指派給 object),必須進行「裝箱」;反之,從堆積取出值類型則需「拆箱」。

int i = 123;
object obj = i;        // Boxing
if (obj is int)
    int j = (int)obj;  // Unboxing

為何要減少裝箱/拆箱?

  • 堆積操作效率較堆疊低。
  • 堆積上配置的記憶體需由 GC 回收,增加執行期負擔。

常見情境與優化策略

1. 格式化輸出

Console.WriteLine、String.Format 等方法參數為 object,傳入值類型會觸發裝箱。解決方法:預先呼叫 ToString() 轉為字串(參考類型),避免裝箱。

// 原本:會裝箱
Console.WriteLine("Number list:{0}, {1}, {2}", 1, 2, 3);

// 優化:無裝箱
Console.WriteLine("Number list:{0}, {1}, {2}", 1.ToString(), 2.ToString(), 3.ToString());

2. 集合存儲值類型(ArrayList、Hashtable 等)

將值類型存入非泛型集合會發生裝箱,且取出時需拆箱。更嚴重的是,拆箱取得的是複本,修改複本不影響集合內原物件:

struct Person { public string Name; }
ArrayList list = new ArrayList();
Person p = new Person { Name = "OldName" };
list.Add(p);                    // 裝箱
p = (Person)list[0];            // 拆箱得複本
p.Name = "NewName";             // 修改複本
Console.WriteLine(((Person)list[0]).Name); // 輸出 "OldName"

若嘗試直接修改 ((Person)list[0]).Name = "NewName",編譯器會報錯,因為拆箱產生的是暫存變數,不可修改。

透過介面避免裝箱並正確修改

定義介面,讓結構實作該介面。集合存入時仍會裝箱,但透過介面參考存取時,暫存變數型別為介面(參考類型),修改會直接反映到原物件:

interface IPersonName { string Name { get; set; } }
struct Person : IPersonName { public string Name { get; set; } }

ArrayList list = new ArrayList();
list.Add(new Person { Name = "OldName" }); // 裝箱一次
((IPersonName)list[0]).Name = "NewName";   // 透過介面修改,無拆箱
Console.WriteLine(((Person)list[0]).Name); // 輸出 "NewName"

原理:拆箱為值類型產生暫存複本;拆箱為介面類型產生指向原物件的參考。注意:若介面成員回傳值類型,仍會發生拆箱,無法減少開銷。

總結

頻繁裝箱/拆箱會拖垮效能。開發時應盡量:

  • 格式化輸出前先 ToString()。
  • 優先使用泛型集合(List<T> 等)避免非泛型集合的裝箱。
  • 若必須用非泛型集合存值類型,考慮實作介面以利修改並減少拆箱。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved