枚举和表现

Ray*_*Ray 26 c# performance enums dictionary casting

我的应用程序有很多不同的查找值,这些值永远不会改变,例如美国.我想使用枚举,而不是将它们放入数据库表中.

但是,我确实意识到这样做需要一些枚举和大量的"int"和"string"来自我的枚举.

另外,我看到有人提到使用Dictionary <>作为查找表,但枚举实现似乎更清晰.

所以,我想问一下是否保留并传递很多枚举并将它们转换为性能问题,还是应该使用查找表方法,哪个表现更好?

编辑:需要转换为ID以存储在其他数据库表中.

Jon*_*eet 35

int枚举到枚举非常便宜......它比字典查找更快.基本上它是一个无操作,只是将位复制到具有不同概念类型的位置.

将字符串解析为枚举值将稍微慢一些.

我怀疑这对你来说是一个瓶颈但是你这样做,说实话......不知道你在做什么,有点难以推荐超出正常的"写最简单,模式可读和可管理的可维护代码,然后检查它是否运行良好."

  • @CADBloke:我希望如此,是的.但是试试这对你来说很重要:) (2认同)

Str*_*ior 16

你不会注意到两者之间在性能上的巨大差异,但我仍然建议使用词典,因为它将在未来为你提供更多的灵活性.

首先,C#中的Enum不能像Java一样自动拥有与之关联的类,因此如果要将其他信息与状态(全名,Capital City,Postal缩写等)相关联,则创建一个UnitedState类将所有信息打包到一个集合中更容易.

而且,即使你认为这个值永远不会改变,它也不是完全不可改变的.例如,你可以想象有一个新的要求包括领土.或者,您可能需要允许加拿大用户查看加拿大省的名称.如果您将此集合视为任何其他数据集合(使用存储库从中检索值),您稍后可以选择更改存储库实现以从其他来源(数据库,Web服务,会话等)提取值. ).枚举不太通用.

编辑

关于性能参数:请记住,您不只是将Enum强制转换为int:您还在该枚举上运行ToString(),这会增加相当多的处理时间.考虑以下测试:

const int C = 10000;
int[] ids = new int[C];
string[] names = new string[C];
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i< C; i++)
{
    var id = (i % 50) + 1;
    names[i] = ((States)id).ToString();
}
sw.Stop();
Console.WriteLine("Enum: " + sw.Elapsed.TotalMilliseconds);
var namesById = Enum.GetValues(typeof(States)).Cast<States>()
                .ToDictionary(s => (int) s, s => s.ToString());
sw.Restart();
for (int i = 0; i< C; i++)
{
    var id = (i % 50) + 1;
    names[i] = namesById[id];
}
sw.Stop();
Console.WriteLine("Dictionary: " + sw.Elapsed.TotalMilliseconds);
Run Code Online (Sandbox Code Playgroud)

结果:

Enum: 26.4875
Dictionary: 0.7684
Run Code Online (Sandbox Code Playgroud)

因此,如果性能确实是您最关心的问题,那么词典绝对是您的选择.然而,我们在这里谈论如此快速的时间,在我甚至不关心速度问题之前,还有其他六个问题需要解决.

C#中的枚举不是为了提供值和字符串之间的映射而设计的.它们旨在提供强类型常量值,您可以在代码中传递它们.这样做的两个主要优点是:

  1. 你有一个额外的编译器检查线索,以帮助您避免以错误的顺序传递参数,等等.
  2. 您可以说"States.Oklahoma",而不是在代码中添加"神奇"数字值(例如"42"),这使您的代码更具可读性.

与Java不同,C#不会自动检查强制转换值以确保它们是有效的(myState = (States)321),因此如果不手动执行,则不会对输入进行任何运行时数据检查.如果您没有明确引用状态的代码("States.Oklahoma"),那么您不会从上面的#2获得任何值.这使得#1成为使用枚举的唯一真正原因.如果这是一个足够好的理由,那么我建议使用枚举而不是整数作为键值.然后,当您需要字符串或与状态相关的其他值时,请执行字典查找.

这是我如何做到的:

public enum StateKey{
    AL = 1,AK,AS,AZ,AR,CA,CO,CT,DE,DC,FM,FL,GA,GU,
    HI,ID,IL,IN,IA,KS,KY,LA,ME,MH,MD,MA,MI,MN,MS,
    MO,MT,NE,NV,NH,NJ,NM,NY,NC,ND,MP,OH,OK,OR,PW,
    PA,PR,RI,SC,SD,TN,TX,UT,VT,VI,VA,WA,WV,WI,WY,
}

public class State
{
    public StateKey Key {get;set;}
    public int IntKey {get {return (int)Key;}}
    public string PostalAbbreviation {get;set;}

}

public interface IStateRepository
{
    State GetByKey(StateKey key);
}

public class StateRepository : IStateRepository
{
    private static Dictionary<StateKey, State> _statesByKey;
    static StateRepository()
    {
        _statesByKey = Enum.GetValues(typeof(StateKey))
        .Cast<StateKey>()
        .ToDictionary(k => k, k => new State {Key = k, PostalAbbreviation = k.ToString()});
    }
    public State GetByKey(StateKey key)
    {
        return _statesByKey[key];
    }
}

public class Foo
{
    IStateRepository _repository;
    // Dependency Injection makes this class unit-testable
    public Foo(IStateRepository repository) 
    {
        _repository = repository;
    }
    // If you haven't learned the wonders of DI, do this:
    public Foo()
    {
        _repository = new StateRepository();
    }

    public void DoSomethingWithAState(StateKey key)
    {
        Console.WriteLine(_repository.GetByKey(key).PostalAbbreviation);
    }
}
Run Code Online (Sandbox Code Playgroud)

这条路:

  1. 你可以传递代表一个状态的强类型值,
  2. 如果给出无效输入,您的查找将获得快速失败的行为,
  3. 您可以轻松更改实际状态数据在未来的位置,
  4. 您可以在以后轻松地将状态相关数据添加到State类中,
  5. 您可以在将来轻松添加新的州,地区,地区,省份或其他任何其他内容.
  6. 从int获取名称仍然比使用时快15倍Enum.ToString().

[咕噜]

  • @TMN:即使枚举更快,我们也谈论的是如此高的速度,以至于在绝大多数应用中它都不会引人注目.我很难建议牺牲灵活性来实现性能的微小改进.然而,事实证明,对于他正在谈论的事情,字典查找实际上要快得多.看到我更新的答案. (3认同)