我的应用程序有许多不同的检索值,这些值从不改变,例如美国州。我想使用枚举而不是将它们放入数据库表中。
但是,我意识到这样做涉及到一些枚举和很多从“int”和“string”到我的枚举的转换。
另外,我看到有人提到使用Dictionary<>作为查找表,但是枚举实现似乎更加简洁。
所以,我想问一下保留大量枚举并进行转换是否会影响性能,还是应该使用查找表的方法来获得更好的性能?
编辑:需要进行强制类型转换是因为ID需要存储在其他数据库表中。
我的应用程序有许多不同的检索值,这些值从不改变,例如美国州。我想使用枚举而不是将它们放入数据库表中。
但是,我意识到这样做涉及到一些枚举和很多从“int”和“string”到我的枚举的转换。
另外,我看到有人提到使用Dictionary<>作为查找表,但是枚举实现似乎更加简洁。
所以,我想问一下保留大量枚举并进行转换是否会影响性能,还是应该使用查找表的方法来获得更好的性能?
编辑:需要进行强制类型转换是因为ID需要存储在其他数据库表中。
将int
转换为枚举类型是非常便宜的...它比字典查找更快。基本上这只是一个无操作,只是将位复制到具有不同概念类型的位置。
将字符串解析为枚举值会慢一些。
但是,老实说,我怀疑这不会成为您的瓶颈...如果不知道更多您在做什么的信息,很难给出建议,除了正常的“编写最简单,最可读和易于维护的代码,然后检查其性能是否足够。”
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);
结果:
Enum: 26.4875
Dictionary: 0.7684
myState = (States)321
),因此,如果没有手动进行运行时数据检查,则无法对输入进行任何运行时数据检查。如果没有引用明确指向州("States.Oklahoma"),那么您将无法从上述第2个优点中获得任何价值。这使得第1个优点成为使用枚举的唯一真正原因。如果这个原因对您来说足够好,那么我建议您使用枚举而不是int作为键值。然后,在需要与状态相关联的字符串或其他值时,执行Dictionary查找。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);
}
}
这样做有以下好处:
Enum.ToString()
仍然快约15倍。[grunt]
Public MustInherit Class AbstractTypeSafeEnum
Private Shared ReadOnly syncroot As New Object
Private Shared masterValue As Integer = 0
Protected ReadOnly _name As String
Protected ReadOnly _value As Integer
Protected Sub New(ByVal name As String)
Me._name = name
SyncLock syncroot
masterValue += 1
Me._value = masterValue
End SyncLock
End Sub
Public ReadOnly Property value() As Integer
Get
Return _value
End Get
End Property
Public Overrides Function ToString() As String
Return _name
End Function
Public Shared Operator =(ByVal ats1 As AbstractTypeSafeEnum, ByVal ats2 As AbstractTypeSafeEnum) As Boolean
Return (ats1._value = ats2._value) And Type.Equals(ats1.GetType, ats2.GetType)
End Operator
Public Shared Operator <>(ByVal ats1 As AbstractTypeSafeEnum, ByVal ats2 As AbstractTypeSafeEnum) As Boolean
Return Not (ats1 = ats2)
End Operator
End Class
这里是一个枚举:
Public NotInheritable Class EnumProcType
Inherits AbstractTypeSafeEnum
Public Shared ReadOnly CREATE As New EnumProcType("Création")
Public Shared ReadOnly MODIF As New EnumProcType("Modification")
Public Shared ReadOnly DELETE As New EnumProcType("Suppression")
Private Sub New(ByVal name As String)
MyBase.New(name)
End Sub
End Class
添加国际化功能变得更加容易了。
抱歉,它是用VB和法语编写的。
干杯!
或者您可以使用常量
如果问题是“枚举转换比访问字典项更快吗?”,那么其他回答涉及性能的各个方面就有意义了。
但是这里的问题似乎是“当我需要将它们的值存储到数据库表中时,枚举转换会对应用程序性能产生负面影响吗?”。
如果是这样,我不需要运行任何测试来说,将数据存储在数据库表中总是比转换枚举或执行其ToString()慢几个数量级。
在这种情况下,我认为重要的是代码的可读性和可维护性。在简单的情况下,枚举可以干净地完成工作,但我同意其他答案,字典在长期内更加灵活。
使用 [Flags]
属性。如果你想要获取两个值之间的共同字段,可能有比给它分配一个新值更好的方法。例如:
[Flags]
public enum MyEnum
{
statusA = 1,
statusB = 2,
both = status1 | status2 //This value = 3 ( 1+2 )
}
status1 << status2
) - Jeremy Caney枚举类型在性能方面表现非常优秀,尤其是相比于字典。枚举类型只使用单个字节。但是为什么需要进行强制转换呢?似乎应该在任何地方都使用枚举类型。
int
。 - LukeH