Unity 性能优化: C#枚举Key字典

问题:Unity 的 C# 脚本中,使用 enum 作字典 Dictionary<TKey,TValue> 的 key 时,key 的 Equals() 相等比较存在装箱开销。

解决:要避免 Key 相等比较引入的装箱开销,泛型字典的构造器提供了接受比较器 Comparer 的重载。因此,我们提供自己的 enum 比较器就行了。

进一步:自定义 enum 比较器很简单方便。只是,需要为用到的每个枚举类型都写个比较器,既然都差不多,能不能偷个懒呢 ^_^

下面考虑用下泛型,但由于 Enum 本身并没有实现 IEquatable<> 接口,直接调用其 Equals() 方法还是会装箱。那么,我们尝试下别的方式:

再次解决(部分):仅针对 int 类型的枚举。可以利用 int.GetHashCode() 就是其本身的特性,从而把 int 值的比较等价为其 HashCode 的比较,避开 Equals() 引入的装箱开销。(代码附后)

注意:这种方法仅是思路探索,如果想要实用,请自行做充分测试。

完整解决:微软 .Net 4.0 版本的泛型字典已经完整支持 enum key 了。所以,想要完美的体验,就努力升级吧。

ps:我用的 Unity 版本仅支持 .Net 2.0 版本 ,所以泛型字典还没有针对 enum key 做优化,但是我看到微软的 .Net 4.0 版本中已经针对 enum key 做了优化,至于最早是哪个 .Net 版本开始的优化,我并没有深入调查。这里的尝试也参考了 .Net 4.0 的优化。

代码示例:

// EnumKeyDictionary.cs
public class EnumKeyDictionary<TKey, TValue> : System.Collections.Generic.Dictionary<TKey, TValue> where TKey : struct
{
    public EnumKeyDictionary() : base(GetComparer()) { }
    public EnumKeyDictionary(int capacity) : base(capacity, GetComparer()) { }
    public EnumKeyDictionary(IDictionary<TKey, TValue> dictionary) : base(dictionary, GetComparer()) { }

    public EnumKeyDictionary(IEqualityComparer<TKey> comparer) : base(comparer) { }
    public EnumKeyDictionary(int capacity, IEqualityComparer<TKey> comparer) : base(capacity, comparer) { }
    public EnumKeyDictionary(IDictionary<TKey, TValue> dictionary, IEqualityComparer<TKey> comparer) : base(dictionary, comparer) { }


    static IEqualityComparer<TKey> GetComparer()
    {
        System.Type typeHandle = typeof(TKey);
        if (typeHandle.IsEnum)
        {
            // 利用 int.GetHashCode() 就是其本身
            System.Type underlyingType = System.Enum.GetUnderlyingType(typeHandle);
            if (underlyingType == typeof(int) ||
                underlyingType == typeof(byte) ||
                underlyingType == typeof(ushort) ||
                underlyingType == typeof(uint))
            {
                return IntEnumEqualityComparer<TKey>.GetComparer();
            }
        }
        return null;
    }
}


// EqualityComparer.cs
 public class IntEnumEqualityComparer<T> : IEqualityComparer<T> where T : struct
 {
    static IEqualityComparer<T> s_comparer;

    public static IEqualityComparer<T> GetComparer()
    {
        if (s_comparer == null)
        {
            s_comparer = new IntEnumEqualityComparer<T>();
        }
        return s_comparer;
    }

    public bool Equals(T x, T y)
    {
        return x.GetHashCode() == y.GetHashCode();
    }

    public int GetHashCode(T obj)
    {
        return obj.GetHashCode();
    }
}
// test.cs
using System;
using System.Collections.Generic;

public enum CKind
{
	A,
	B=1,
	C=1,
	D,
}

public class Test
{
    static void Test0()
    {
		Dictionary<CKind, int> dic = new EnumKeyDictionary<CKind, int>();
    }
}

C# 泛型比较器的代码片段:

.Net 2.0 版本

.Net 4.0 版本 

Int32.GetHashCode

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值