防止装箱落实到底,只做一半也是失败

  .NET提供struct类型,正确使用可以减少对象数量,从而降低GC压力,提高性能。不过有时候我会发现,某些同学有这方面的意识,但是有时候一疏忽一偷懒,就没有得到相应的效果了。这里举一个真实的例子:假设我们要将一对int作为字典的键,用于映射到某些数据,那么你会怎么做?当然我们可以直接使用Tuple<int, int>,但这样就可能产生大量的对象。于是我们打算使用自定义的值类型:

  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<T>或是Dictionary<TKey, TValue>集合其实都不会直接调用GetHashCode和Equals方法,都是通过一个IEqualityComparer<T>对象来委托调用的:

  public interface IEqualityComparer<in T> {

  bool Equals(T x, T y);

  int GetHashCode(T obj);

  }

  假如在创建集合的时候没有提供比较器,则会使用默认的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>();

  }

  可以看出,根据不同的情况它会使用各式不同的比较器。其中最适合我们的自然就是实现IEquatable<T>接口的分支了。于是我们可以这么做:

  struct MyKey : IEquatable<MyKey> {

  // ...

  public bool Equals(MyKey that) {

  // ...

  }

  }

  这才是最终符合我们要求的做法。

来至:近乎sns开发分享社区

时间: 2024-10-11 00:30:11

防止装箱落实到底,只做一半也是失败的相关文章

解密小米:到底想做什么?

即使估值已经超过450亿美元,小米依然是一家很饥渴的公司. 这家公司的创始人兼首席执行官雷军在最近的一个月中,带着他的自拍杆多次出现在了全球媒体的镜头中,46岁的他看上去意得志满.3月15日,他在朋友圈中贴出了李克强总理答记者问的一段话——“最近互联网上流行的一个词叫风口,我想站在‘互联网+’的风口上顺势而为,会使中国经济飞起来.” 雷军成功地将他的“风口”和“顺势而为”理论输出到了国家领导层.他的另一个身份是全国人大代表,根据耶鲁大学Rory Truex的调查,如果一家公司的CEO当上全国人大

勿忘“9·11”:BCM不能只做表面文章

硝烟散尽,伤痛仍在. "9·11" ,为了不能忘却的纪念! 2001年9月11日,发生在美国的"9·11"事件震惊全球.这一事件也成为灾难恢复和业务连续性领域的标志性事件.随着时间的流逝,再提起"9·11" 这个数字,很多人已经没有当初那么敏感.不过,这一事件对整个灾难恢复和业务连续性行业的发展却有着极为重要的影响.很多人就是从那一天起才意识到灾难恢复的重要性和必要性. 巧合的是,在今年的"9·11"纪念日,主题为"

又是高考--只做最有用的事

今天又是高考的时候.回想当年自己为什么要复读,为什么别人做一次的事情我要做两次? 如今自己大三了,接触到的人和事也越来越多,更重要的是在大学里,我的眼里不只是有学习.高中那几年现在觉得有点浪费了.因为实现高考成绩达到自己的理想,并不需要三年的时间,而我却用了四年.如今我认为,如果当年没有把眼光放得那么狭隘(眼里只有高考),用更多的眼光去观察和学习身边的人的观念.观点.思维.方法等等,也许我得到的会比高考成绩多得多,也更加有用.现在回想起来,高考只是也只能是高考,别无它用. 当年的高考,眼里只有学

外贸网络推广:只做有好的结果的事

外贸网络推广:只做有好的结果的事 原文出处:http://www.szxnl.net/trade-promotion-network/ 我们都明白:任何事情去做,必然有结果,但不一定是好的结果,也不一定是我们所期望的. 如何把事情做到有好的结果? 很简单, 要做好一个事情,就是要把所有参与此事的人,都获得有益结果.否则,就会导致失败,这是或早或迟的事. 这是一条亘古不变宇宙真理. 你可以拿世间任何事情来套这个真理或法则. 比如,男婚女嫁,须双方自主意愿,一个愿娶,一个愿嫁,否则会出问题; 再比如

让你的代码只做一件事情

还记得周星驰主演的电影<国产凌凌漆>有一段让人捧腹的情节, 在凌凌漆和司令对战时刻, 达文西半路杀了出来, 扬言要让司令尝一下他新发明的集10种致命武器于一身的「要你命3000」的威力, 传说这是胜过任何武器10倍威力的杀人利器,然而,还没等武器开锋,司令一枪就把达文西给打残了.周星驰的电影就是这么无厘头,但通过这个情节来仔细观察我们的世界,会发现一种规律,我们人类生产的任何工具,都是针对解决特定问题的, 换句话说, 很多工具功能都是单一性的, 多功能的事物似乎没有那么容易流行开来,就像文西发

上涨、下跌、震荡,我只做下跌 (有钱人赚钱太有心机!

http://guba.eastmoney.com/news,gssz,191927844.html 昨天下午,一个做了10年期货操盘的朋友跟我们分享如何做期货,他讲的东西其实和我曾经学习到的东西差不多,但是我却心里一颤,带给了我思想和观念上的质变. 还有一个做股票的朋友,说了他做股票的情况.他们的操作策略都非常简单,但实际上对绝大部分人来说是非常困难的.大道至简,要理解并践行这句话真不是件容易的事情. 1做期货的朋友说: 1.我最重要的工作不是分析基本面,因为所谓的基本面信息都是N手信息,而且

代码简洁之二:函数只做一件事儿

函数应该做一件事.做好这件事.只做这一件事. 所以我们简化代码的一个简单方式就是不断拆分函数(Extract Method),一直拆分,拆分到不能再分出一个函数为止. 拆函数的过程就是一个概括目的.步骤,提取抽象层次动名词的过程.不要做只是解释代码的简单概括,要让函数中的语句处于一个相同抽象层次,如果是更细节的事儿,请再进一步拆分出一个函数出来.让代码拥有自顶向下的阅读顺序. 以我之前写的一个列表显示的action(MVC框架里面的某个控制器里面的一个方法),最开始代码是这样的: // 接收查询

只做最关键的事

我的工作与职业: 软件产品与服务的设计与创造: 重要事件的取舍.决策与处理. 我的生活与业余: 遇见终身伴侣,组建家庭. 博客以传播有益知识和有益思想. 职业特征:智力密集型 逻辑分析与推理,想象力 组织与表达,思考与决策,丰富的内心 只做最关键的事: 运动强身,足量睡眠,良好饮食,每日挑战,思考规划,慢静之心,自省,静思. 1.   运动强身,增强防卫能力: 每天早晚半小时锻炼,室内体操: 周末漫步远行,适当骑行: 每半年定期检查身体. 2.   每天睡足7小时,23:00-7:00: 午休:

拥有梦想的人不做选择题,他们只做证明题

是安于现在的生活并且学着享受庸常,还是甘冒下坠的风险振翅飞往远方? 这是我最近经常看到的问题.说实话,我也觉得非常惊奇,竟然有那么多人,觉得现实在一点点埋葬自己的梦想,同时又没有足够的勇气跨出一步.每次说到看不到的山那头,海的那一端,总有无数颗小心在各个地方黯然破碎.仿佛一夜之间经过了四十个星球,却没有一个星星上能种出玫瑰花来. 人们写信来,索要帮助和建议.但是我又能做什么呢?我的人生是我的人生,我的经验是我的经验,未必对你有用.况且,我安于这样的生活,命运如此安排,而换做别人,怕是不能把这其中