.NET避免装箱的方法
.NET提供struct类型,正确使用可以减少对象数量,从而降低GC压力,提高性能。不过有时候我会发现,某些同学有这方面的意识,但是有时候一疏忽一偷懒,就没有得到相应的效果了。这里举一个真实的例子:假设我们要将一对int
作为字典的键,用于映射到某些数据,那么你会怎么做?当然我们可以直接使用Tuple
,但这样就可能产生大量的对象。于是我们打算使用自定义的值类型:
private struct MyKey {private readonly int _a; private readonly int _b; public MyKey(int a, int b) {_a = a; _b = b; }}
这么做正确吗?假如你做一下测试,会发现它已经可以“正确使用”了,但实际上还是错误的。我们用它来做字典的键,会依赖
GetHashCode
和Equals
两个方法,由于MyKey
没有提供这两个方法,就会自动使用System.ValueType
里的实现,这便引起了装箱。好吧,那么我们就来实现一下:
private struct MyKey {// ...public override int GetHashCode() {// ...}public override bool Equals(object that) {// ...}}
那么现在呢?可能现在您就会比较容易意识到,即便
GetHashCode
已经没有问题了,但是Equals
方法还是会引起装箱,因为that
参数依然是object
类型。怎么破?当然有办法,因为像
HashSet
或是Dictionary
集合其实都不会直接调用GetHashCode
和Equals
方法,都是通过一个IEqualityComparer
对象来委托调用的:public interface IEqualityComparer{bool Equals(T x, T y); int GetHashCode(T obj); }
假如在创建集合的时候没有提供比较器,则会使用默认的
EqualityComparer.Default
对象,它的构造方法是这样的:private static EqualityComparerCreateComparer () {Contract.Ensures(Contract.Result >() != null); RuntimeType t = (RuntimeType)typeof(T); // Specialize type byte for performance reasons if (t == typeof(byte)) {return (EqualityComparer )(object)(new ByteEqualityComparer()); }// If T implements IEquatable return a GenericEqualityComparer if (typeof(IEquatable ).IsAssignableFrom(t)) {return (EqualityComparer )RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(GenericEqualityComparer ), t); }// If T is a Nullable where U implements IEquatable return a NullableEqualityComparerif (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>)) {RuntimeType u = (RuntimeType)t.GetGenericArguments()[0]; if (typeof(IEquatable<>).MakeGenericType(u).IsAssignableFrom(u)) {return (EqualityComparer )RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(NullableEqualityComparer ), u); }}// If T is an int-based Enum, return an EnumEqualityComparer // 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 )RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(EnumEqualityComparer ), t); }// Otherwise return an ObjectEqualityComparer return new ObjectEqualityComparer (); }
可以看出,根据不同的情况它会使用各式不同的比较器。其中最适合我们的自然就是实现
IEquatable
接口的分支了。于是我们可以这么做:struct MyKey : IEquatable{// ...public bool Equals(MyKey that) {// ...}}
【.NET避免装箱的方法】这才是最终符合我们要求的做法。
以上所述是小编给大家介绍的.NET避免装箱的方法,希望对大家有所帮助。在此也非常感谢大家对脚本之家网站的支持!
推荐阅读
- java|自学java(2)
- 通过Dapr实现一个简单的基于.net的微服务电商系统(二十)——Saga框架实现思路分享
- Asp.Net|Asp.Net Core: Swagger 与 Identity Server 4
- .NET|.NET Core使用flyfire.CustomSerialPort实现Windows/Linux跨平台串口通讯
- 避免在公众场合起冲突,是每对夫妻都应该明白的事
- 通过Dapr实现一个简单的基于.net的微服务电商系统(十九)——分布式事务之Saga模式
- 洗脑术|洗脑术 打造八面玲珑的关系需要避免的六种情况
- ASP.NET|ASP.NET Core应用开发思维导图
- java|微软认真聆听了开源 .NET 开发社区的炮轰( 通过CLI 支持 Hot Reload 功能)
- 集装箱活动房一般是多大的规格