.NET避免裝箱的方法
.NET提供struct類型,正確使用可以減少對象數(shù)量,從而降低GC壓力,提高性能。不過有時候我會發(fā)現(xiàn),某些同學有這方面的意識,但是有時候一疏忽一偷懶,就沒有得到相應的效果了。這里舉一個真實的例子:假設我們要將一對int
作為字典的鍵,用于映射到某些數(shù)據(jù),那么你會怎么做?當然我們可以直接使用Tuple<int, int>
,但這樣就可能產(chǎn)生大量的對象。于是我們打算使用自定義的值類型:
private struct MyKey { private readonly int _a; private readonly int _b; public MyKey(int a, int b) { _a = a; _b = b; } }
這么做正確嗎?假如你做一下測試,會發(fā)現(xiàn)它已經(jīng)可以“正確使用”了,但實際上還是錯誤的。我們用它來做字典的鍵,會依賴GetHashCode
和Equals
兩個方法,由于MyKey
沒有提供這兩個方法,就會自動使用System.ValueType
里的實現(xiàn),這便引起了裝箱。
好吧,那么我們就來實現(xiàn)一下:
private struct MyKey { // ... public override int GetHashCode() { // ... } public override bool Equals(object that) { // ... } }
那么現(xiàn)在呢?可能現(xiàn)在您就會比較容易意識到,即便GetHashCode
已經(jīng)沒有問題了,但是Equals
方法還是會引起裝箱,因為that
參數(shù)依然是object
類型。
怎么破?當然有辦法,因為像HashSet<T>
或是Dictionary<TKey, TValue>
集合其實都不會直接調(diào)用GetHashCode
和Equals
方法,都是通過一個IEqualityComparer<T>
對象來委托調(diào)用的:
public interface IEqualityComparer<in T> { bool Equals(T x, T y); int GetHashCode(T obj); }
假如在創(chuàng)建集合的時候沒有提供比較器,則會使用默認的EqualityComparer<T>.Default
對象,它的構造方法是這樣的:
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ù)不同的情況它會使用各式不同的比較器。其中最適合我們的自然就是實現(xiàn)IEquatable<T>
接口的分支了。于是我們可以這么做:
struct MyKey : IEquatable<MyKey> { // ... public bool Equals(MyKey that) { // ... } }
這才是最終符合我們要求的做法。
以上所述是小編給大家介紹的.NET避免裝箱的方法,希望對大家有所幫助。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
相關文章
ASP.NET小結之MVC, MVP, MVVM比較以及區(qū)別(一)
MVC, MVP和MVVM都是用來解決界面呈現(xiàn)和邏輯代碼分離而出現(xiàn)的模式。以前只是對它們有部分的了解,沒有深入的研究過,對于一些里面的概念和區(qū)別也是一知半解?,F(xiàn)在一邊查資料,并結合自己的理解,來談一下對于這三種模式思想的理解,以及它們的區(qū)別。歡迎各位高手拍磚。2014-05-05開啟SQLSERVER數(shù)據(jù)庫緩存依賴優(yōu)化網(wǎng)站性能
2010-04-04