C# 不带装箱的System.Enum字典的比较器

C# 不带装箱的System.Enum字典的比较器,c#,unity3d,garbage-collection,C#,Unity3d,Garbage Collection,当我试图创建字典时,遇到了一个问题,其中的键是System.Enum。问题是,像这样的字典分配垃圾是因为默认的EqualityComparer不是最好的。我试着写我自己的比较器,但没有成功。这有可能吗 public enum MyEnum { One, Two, Three } public Dictionary<Enum, string> dict = new Dictionary<Enum, string>(); public void Test(

当我试图创建字典时,遇到了一个问题,其中的键是System.Enum。问题是,像这样的字典分配垃圾是因为默认的EqualityComparer不是最好的。我试着写我自己的比较器,但没有成功。这有可能吗

    public enum MyEnum
{
    One, Two, Three
}

public Dictionary<Enum, string> dict = new Dictionary<Enum, string>();

public void Test()
{
    this.dict.Add(MyEnum.One, "One");
    this.dict.Add(MyEnum.Two, "Two");
    this.dict.Add(MyEnum.Three, "Three");

    string result;
    this.dict.TryGetValue(MyEnum.Two, out result); // <-- memory alocation :-(
}
公共枚举MyEnum
{
一,二,三
}
公共字典dict=新字典();
公开无效测试()
{
这个.dict.Add(MyEnum.One,“One”);
this.dict.Add(MyEnum.Two,“Two”);
这个.dict.Add(MyEnum.Three,“Three”);
字符串结果;

this.dict.TryGetValue(MyEnum.Two,out result);//在注释中看到您的示例,这是为了统一,请注意。它讨论了使用脚本对象而不是枚举作为字典键

你要做的就是

public class Program
{
    protected Dictionary<ScriptableObject, string> dict = new Dictionary<ScriptableObject, string>();
}

public class ProgramChild1 : Program
{
    public void Test()
    {
        dict.Add(MyEnum1.One.Instance, "One");
        dict.Add(MyEnum1.Two.Instance, "Two");
        dict.Add(MyEnum1.Three.Instance, "Three");
        string result;
        dict.TryGetValue(MyEnum1.Two.Instance, out result);
    }   
}

public class ProgramChild2 : Program
{

    public void Test()
    {
        dict.Add(MyEnum2.Four.Instance, "One");
        dict.Add(MyEnum2.Five.Instance, "Two");
        dict.Add(MyEnum2.Six.Instance, "Three");
        string result;
        dict.TryGetValue(MyEnum2.Five.Instance, out result);
    }
}

//Each class goes in to its own .cs file, Put them in two folders `MyEnum1` and `MyEnum2`
namespace MyEnum1
{
    public class One : ScriptableObject
    {
        private static One _inst;
        public static One Instance
        {
            get
            {
                if (!_inst)
                    _inst = Resources.FindObjectOfType<One>();
                if (!_inst)
                    _inst = CreateInstance<One>();
                return _inst;
            }
        }
    }
}  

namespace MyEnum1
{
    public class Two : ScriptableObject
    {
        private static Two _inst;
        public static Two Instance
        {
            get
            {
                if (!_inst)
                    _inst = Resources.FindObjectOfType<Two>();
                if (!_inst)
                    _inst = CreateInstance<Two>();
                return _inst;
            }
        }
    }
}

namespace MyEnum1
{    
    public class Three : ScriptableObject
    {
        private static Three _inst;
        public static Three Instance
        {
            get
            {
                if (!_inst)
                    _inst = Resources.FindObjectOfType<Three>();
                if (!_inst)
                    _inst = CreateInstance<Three>();
                return _inst;
            }
        }
    }
}

namespace MyEnum2
{    
    public class Four : ScriptableObject
    {
        private static Four_inst;
        public static Four Instance
        {
            get
            {
                if (!_inst)
                    _inst = Resources.FindObjectOfType<Four>();
                if (!_inst)
                    _inst = CreateInstance<Four>();
                return _inst;
            }
        }
    }
}

namespace MyEnum2
{    
    public class Five : ScriptableObject
    {
        private static Five _inst;
        public static Five Instance
        {
            get
            {
                if (!_inst)
                    _inst = Resources.FindObjectOfType<Five>();
                if (!_inst)
                    _inst = CreateInstance<Five>();
                return _inst;
            }
        }
    }
}

namespace MyEnum2
{    
    public class Six : ScriptableObject
    {
        private static Six _inst;
        public static Six Instance
        {
            get
            {
                if (!_inst)
                    _inst = Resources.FindObjectOfType<Six>();
                if (!_inst)
                    _inst = CreateInstance<Six>();
                return _inst;
            }
        }
    }
}

您应该编写一个实现接口IEqualityComparer的类

class MyEnumComparer : IEqualityComparer<MyEnum> { ... }
类MyEnumComparer:IEqualityComparer{…}
这意味着您需要实现IEqualityComparer接口定义的bool Equals(MyEnum,MyEnum)和int-GetHashCode(MyEnum)函数

最后,在创建字典时,请使用接收IEqualityComparer实例的构造函数重载,如下所示:

static MyEnumComparer myEnumComparer = new MyEnumComparer();
...
Dictionary<MyEnum, string> dict = new Dictionary<MyEnum, string>(myEnumComparer);
bool contained = enumArray.Contains(MyEnum.someValue, EnumComparer<MyEnum>.Default);


public static class Extensions
{
    public static bool Contains<T>(this T[] array, T value, IEqualityComparer<T> equalityComparer)
    {
        if (array == null)
        {
            throw new ArgumentNullException("array");
        }
        return Extensions.IndexOf<T>(array, value, 0, array.Length, equalityComparer) >= 0;
    }

    public static int IndexOf<T>(this T[] array, T value, IEqualityComparer<T> equalityComparer)
    {
        if (array == null)
        {
            throw new ArgumentNullException("array");
        }
        return Extensions.IndexOf<T>(array, value, 0, array.Length, equalityComparer);
    }

    public static int IndexOf<T>(this T[] array, T value, int startIndex, int count, IEqualityComparer<T> equalityComparer)
    {
        if (array == null)
        {
            throw new ArgumentNullException("array");
        }
        if (count < 0 || startIndex < array.GetLowerBound(0) || startIndex - 1 > array.GetUpperBound(0) - count)
        {
            throw new ArgumentOutOfRangeException();
        }

        int num = startIndex + count;
        for (int i = startIndex; i < num; i++)
        {
            if (equalityComparer.Equals(array[i], value))
            {
                return i;
            }
        }
        return -1;
    }
}
static MyEnumComparer MyEnumComparer=new MyEnumComparer();
...
Dictionary dict=新词典(myEnumComparer);

无需装箱,无需堆分配。速度非常快。无需为每个枚举编写特定的比较器

这个版本可以在任何枚举上工作,只要它的底层类型不超过32位(所以byte、ushort、uint都可以)

使用系统;
使用System.Collections.Generic;
使用System.Runtime.InteropServices;
公共密封类枚举比较器:IEqualityComparer
{
[StructLayout(LayoutKind.Explicit)]
专用结构变压器
{
[字段偏移量(0)]
公共交通;
[字段偏移量(0)]
公共int int32;
}
公共静态枚举比较器默认值{get;}=new EnumComparer();
私有枚举比较器()
{
}
公共布尔等于(TA,TB)
{
变压器变压器变压器=新变压器{t=a};
变压器b变压器=新变压器{t=b};
返回aTransformer.int32==b变压器.int32;
}
public int GetHashCode(T值)
{
变压器值变压器=新变压器{t=value};
返回valueTransformer.int32.GetHashCode();
}
}
如果您想将其用于数组,您可能需要创建一些扩展方法,然后您可以这样使用它:

static MyEnumComparer myEnumComparer = new MyEnumComparer();
...
Dictionary<MyEnum, string> dict = new Dictionary<MyEnum, string>(myEnumComparer);
bool contained = enumArray.Contains(MyEnum.someValue, EnumComparer<MyEnum>.Default);


public static class Extensions
{
    public static bool Contains<T>(this T[] array, T value, IEqualityComparer<T> equalityComparer)
    {
        if (array == null)
        {
            throw new ArgumentNullException("array");
        }
        return Extensions.IndexOf<T>(array, value, 0, array.Length, equalityComparer) >= 0;
    }

    public static int IndexOf<T>(this T[] array, T value, IEqualityComparer<T> equalityComparer)
    {
        if (array == null)
        {
            throw new ArgumentNullException("array");
        }
        return Extensions.IndexOf<T>(array, value, 0, array.Length, equalityComparer);
    }

    public static int IndexOf<T>(this T[] array, T value, int startIndex, int count, IEqualityComparer<T> equalityComparer)
    {
        if (array == null)
        {
            throw new ArgumentNullException("array");
        }
        if (count < 0 || startIndex < array.GetLowerBound(0) || startIndex - 1 > array.GetUpperBound(0) - count)
        {
            throw new ArgumentOutOfRangeException();
        }

        int num = startIndex + count;
        for (int i = startIndex; i < num; i++)
        {
            if (equalityComparer.Equals(array[i], value))
            {
                return i;
            }
        }
        return -1;
    }
}
bool contained=enumArray.Contains(MyEnum.someValue,EnumComparer.Default);
公共静态类扩展
{
公共静态bool包含(此T[]数组、T值、IEqualityComparer equalityComparer)
{
if(数组==null)
{
抛出新的ArgumentNullException(“数组”);
}
返回扩展名.IndexOf(array,value,0,array.Length,equalityComparer)>=0;
}
公共静态int IndexOf(此T[]数组,T值,IEqualityComparer equalityComparer)
{
if(数组==null)
{
抛出新的ArgumentNullException(“数组”);
}
返回扩展名.IndexOf(数组,值,0,数组,长度,相等比较);
}
公共静态int IndexOf(此T[]数组、T值、int startIndex、int计数、IEqualityComparer equalityComparer)
{
if(数组==null)
{
抛出新的ArgumentNullException(“数组”);
}
if(count<0 | | startIndexarray.GetUpperBound(0)-count)
{
抛出新ArgumentOutOfRangeException();
}
int num=开始索引+计数;
对于(int i=startIndex;i
你的字典声明中有输入错误吗?你的枚举是
MyEnum
,但是你的字典是
Dictionary
为什么你的字典类型是
而不是
?因为我的字典存储在ma基类中,我每次都用不同的枚举在派生类中填充它。为什么不使用泛型来指定枚举类型?不知道GC,但这就是我的意思