.NET避免裝箱的方法
.NET提供struct類型,正確使用可以減少對(duì)象數(shù)量,從而降低GC壓力,提高性能。不過(guò)有時(shí)候我會(huì)發(fā)現(xiàn),某些同學(xué)有這方面的意識(shí),但是有時(shí)候一疏忽一偷懶,就沒(méi)有得到相應(yīng)的效果了。這里舉一個(gè)真實(shí)的例子:假設(shè)我們要將一對(duì)int作為字典的鍵,用于映射到某些數(shù)據(jù),那么你會(huì)怎么做?當(dāng)然我們可以直接使用Tuple<int, int>,但這樣就可能產(chǎn)生大量的對(duì)象。于是我們打算使用自定義的值類型:
private struct MyKey {
private readonly int _a;
private readonly int _b;
public MyKey(int a, int b) {
_a = a;
_b = b;
}
}這么做正確嗎?假如你做一下測(cè)試,會(huì)發(fā)現(xiàn)它已經(jīng)可以“正確使用”了,但實(shí)際上還是錯(cuò)誤的。我們用它來(lái)做字典的鍵,會(huì)依賴GetHashCode和Equals兩個(gè)方法,由于MyKey沒(méi)有提供這兩個(gè)方法,就會(huì)自動(dòng)使用System.ValueType里的實(shí)現(xiàn),這便引起了裝箱。
好吧,那么我們就來(lái)實(shí)現(xiàn)一下:
private struct MyKey {
// ...
public override int GetHashCode() {
// ...
}
public override bool Equals(object that) {
// ...
}
}那么現(xiàn)在呢?可能現(xiàn)在您就會(huì)比較容易意識(shí)到,即便GetHashCode已經(jīng)沒(méi)有問(wèn)題了,但是Equals方法還是會(huì)引起裝箱,因?yàn)?code>that參數(shù)依然是object類型。
怎么破?當(dāng)然有辦法,因?yàn)橄?code>HashSet<T>或是Dictionary<TKey, TValue>集合其實(shí)都不會(huì)直接調(diào)用GetHashCode和Equals方法,都是通過(guò)一個(gè)IEqualityComparer<T>對(duì)象來(lái)委托調(diào)用的:
public interface IEqualityComparer<in T> {
bool Equals(T x, T y);
int GetHashCode(T obj);
}假如在創(chuàng)建集合的時(shí)候沒(méi)有提供比較器,則會(huì)使用默認(rèn)的EqualityComparer<T>.Default對(duì)象,它的構(gòu)造方法是這樣的:
private static EqualityComparer<T> CreateComparer<T>() {
Contract.Ensures(Contract.Result<EqualityComparer<T>>() != null);
RuntimeType t = (RuntimeType)typeof(T);
// Specialize type byte for performance reasons
if (t == typeof(byte)) {
return (EqualityComparer<T>)(object)(new ByteEqualityComparer());
}
// If T implements IEquatable<T> return a GenericEqualityComparer<T>
if (typeof(IEquatable<T>).IsAssignableFrom(t)) {
return (EqualityComparer<T>)RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter(
(RuntimeType)typeof(GenericEqualityComparer<int>), t);
}
// If T is a Nullable<U> where U implements IEquatable<U> return a NullableEqualityComparer<U>
if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>)) {
RuntimeType u = (RuntimeType)t.GetGenericArguments()[0];
if (typeof(IEquatable<>).MakeGenericType(u).IsAssignableFrom(u)) {
return (EqualityComparer<T>)RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter(
(RuntimeType)typeof(NullableEqualityComparer<int>), u);
}
}
// If T is an int-based Enum, return an EnumEqualityComparer<T>
// See the METHOD__JIT_HELPERS__UNSAFE_ENUM_CAST and METHOD__JIT_HELPERS__UNSAFE_ENUM_CAST_LONG cases in getILIntrinsicImplementation
if (t.IsEnum && Enum.GetUnderlyingType(t) == typeof(int)) {
return (EqualityComparer<T>)RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter(
(RuntimeType)typeof(EnumEqualityComparer<int>), t);
}
// Otherwise return an ObjectEqualityComparer<T>
return new ObjectEqualityComparer<T>();
}可以看出,根據(jù)不同的情況它會(huì)使用各式不同的比較器。其中最適合我們的自然就是實(shí)現(xiàn)IEquatable<T>接口的分支了。于是我們可以這么做:
struct MyKey : IEquatable<MyKey> {
// ...
public bool Equals(MyKey that) {
// ...
}
}這才是最終符合我們要求的做法。
以上所述是小編給大家介紹的.NET避免裝箱的方法,希望對(duì)大家有所幫助。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
相關(guān)文章
把字符串轉(zhuǎn)為HtmlTable演示動(dòng)畫(huà)
怎樣將字符串轉(zhuǎn)為.cs頁(yè)面中的HtmlTable,在論壇上看到了這樣一個(gè)問(wèn)題,想試著把它解決下,感興趣的朋友可以觀看下本文的動(dòng)畫(huà),或許對(duì)你有所幫助2013-03-03
關(guān)于利用RabbitMQ實(shí)現(xiàn)延遲任務(wù)的方法詳解
最近在使用RabbitMQ來(lái)實(shí)現(xiàn)延遲任務(wù)的時(shí)候發(fā)現(xiàn),這其中的知識(shí)點(diǎn)還是挺多的,所以下面這篇文章主要給大家介紹了關(guān)于利用RabbitMQ實(shí)現(xiàn)延遲任務(wù)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下。2017-12-12
asp.net(C#)中上傳大文件的幾中常見(jiàn)應(yīng)用方法
最近博客需要做一個(gè)文件上下載功能,我從網(wǎng)上找了點(diǎn)資料,整理了下希望對(duì)大家有幫助!2008-11-11
asp.net Forms身份驗(yàn)證和基于角色的權(quán)限訪問(wèn)
Forms身份驗(yàn)證用來(lái)判斷是否合法用戶,當(dāng)用戶合法后,再通過(guò)用戶的角色決定能訪問(wèn)的頁(yè)面。2009-09-09
ASP.NET小結(jié)之MVC, MVP, MVVM比較以及區(qū)別(一)
MVC, MVP和MVVM都是用來(lái)解決界面呈現(xiàn)和邏輯代碼分離而出現(xiàn)的模式。以前只是對(duì)它們有部分的了解,沒(méi)有深入的研究過(guò),對(duì)于一些里面的概念和區(qū)別也是一知半解?,F(xiàn)在一邊查資料,并結(jié)合自己的理解,來(lái)談一下對(duì)于這三種模式思想的理解,以及它們的區(qū)別。歡迎各位高手拍磚。2014-05-05

