.NET避免装箱的方法
.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) {
// ...
}
}这才是最终符合我们要求的做法。
以上所述是小编给大家介绍的.NET避免装箱的方法,希望对大家有所帮助。在此也非常感谢大家对脚本之家网站的支持!
相关文章
asp.net下比较两个等长字符串是否含有完全相同字符(忽略字符顺序)
项目中遇到一个好玩的问题,需要比较两个选择区域选择的文字是否一样,就想到将这两个区域中选中的文字链接起来进行两个字符串之间的比较2010-06-06
.NET Framework常用ORM框架iBatis.Net操作数据库的方法
iBatis.Net 是一个轻量级的 ORM 框架,它允许开发者通过直接编写 SQL 查询来操作数据库,并将查询结果映射到对象模型中,本文将通过实际的代码示例,详细介绍如何在 .NET 环境中使用 iBatis.Net 进行数据库操作,感兴趣的朋友一起看看吧2024-08-08
.net+FusionChart实现动态显示的柱状图和饼状图
这篇文章介绍了.net+FusionChart实现动态显示柱状图和饼状图的方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下2022-07-07
详解ASP.NET Core 中基于工厂的中间件激活的实现方法
这篇文章主要介绍了ASP.NET Core 中基于工厂的中间件激活的实现方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下2020-11-11


最新评论