I have an enum which is defined like this:
我有一个enum,定义如下
public enum eRat { A = 0, B=3, C=5, D=8 };
So given value eRat.B
, I want to get the next one which is eRat.C
所以eRat给定值。B,下一个是erat。c
The solution I see is (without range checking)
我看到的解决方案是(没有范围检查)
Array a = Enum.GetValues(typeof(eRat));
int i=0 ;
for (i = 0; i < a.GetLength(); i++)
{
if (a.GetValue(i) == eRat.B)
break;
}
return (eRat)a.GetValue(i+1):
Now that is too much complexity, for something that simple. Do you know any better solution?? Something like eRat.B+1
or Enum.Next(Erat.B)
?
对于这么简单的事情来说,这太复杂了。你知道更好的解决办法吗?就像eRat。B + 1或Enum.Next(Erat.B)?
Thanks
谢谢
20 个解决方案
#1
41
Thanks to everybody for your answers and feedback. I was surprised to get so many of them. Looking at them and using some of the ideas, I came up with this solution, which works best for me:
谢谢大家的回答和反馈。我很惊讶能得到这么多。看看他们,并运用其中的一些想法,我想到了这个对我最有效的解决方案:
public static class Extensions
{
public static T Next<T>(this T src) where T : struct
{
if (!typeof(T).IsEnum) throw new ArgumentException(String.Format("Argumnent {0} is not an Enum", typeof(T).FullName));
T[] Arr = (T[])Enum.GetValues(src.GetType());
int j = Array.IndexOf<T>(Arr, src) + 1;
return (Arr.Length==j) ? Arr[0] : Arr[j];
}
}
The beaty of this approach, that it is simple and universal to use. Implemented as generic extension method, you can call it on any enum this way:
这种方法的优点是,使用起来简单而通用。作为通用扩展方法实现,您可以在任何enum上以以下方式调用:
return eRat.B.Next();
Notice, I am using generalized extension method, thus I don't need to specify type upon call, just .Next()
.
注意,我使用的是通用扩展方法,因此不需要在调用时指定类型,只需. next()。
Thanks again.
再次感谢。
#2
36
Probably a bit overkill, but:
可能有点过头了,但是:
eRat value = eRat.B;
eRat nextValue = Enum.GetValues(typeof(eRat)).Cast<eRat>()
.SkipWhile(e => e != value).Skip(1).First();
or if you want the first that is numerically bigger:
或者如果你想要第一个数字更大:
eRat nextValue = Enum.GetValues(typeof(eRat)).Cast<eRat>()
.First(e => (int)e > (int)value);
or for the next bigger numerically (doing the sort ourselves):
或者对于下一个较大的数字(自己做排序):
eRat nextValue = Enum.GetValues(typeof(eRat)).Cast<eRat>()
.Where(e => (int)e > (int)value).OrderBy(e => e).First();
Hey, with LINQ as your hammer, the world is full of nails ;-p
嘿,LINQ作为你的锤子,世界充满了钉子;-p
#3
23
Do you really need to generalize this problem? Can you just do this instead?
你真的需要概括这个问题吗?你可以这样做吗?
public void SomeMethod(MyEnum myEnum)
{
MyEnum? nextMyEnum = myEnum.Next();
if (nextMyEnum.HasValue)
{
...
}
}
public static MyEnum? Next(this MyEnum myEnum)
{
switch (myEnum)
{
case MyEnum.A:
return MyEnum.B;
case MyEnum.B:
return MyEnum.C;
case MyEnum.C:
return MyEnum.D;
default:
return null;
}
}
#4
12
The problem you're dealing with is because you're trying to get an enum to do something it shouldn't. They're supposed to be type safe. Assigning integral values to an enum is allowed so that you can combine them, but if you want them to represent integral values, use classes or structs. Here's a possible alternative:
您正在处理的问题是,因为您试图获得一个enum来执行它不应该执行的操作。它们应该是类型安全的。为enum分配整数值是允许的,以便您可以组合它们,但是如果您希望它们表示整数值,请使用类或结构。这里有一个可能的替代方法:
public static class eRat
{
public static readonly eRatValue A;
public static readonly eRatValue B;
public static readonly eRatValue C;
public static readonly eRatValue D;
static eRat()
{
D = new eRatValue(8, null);
C = new eRatValue(5, D);
B = new eRatValue(3, C);
A = new eRatValue(0, B);
}
#region Nested type: ERatValue
public class eRatValue
{
private readonly eRatValue next;
private readonly int value;
public eRatValue(int value, eRatValue next)
{
this.value = value;
this.next = next;
}
public int Value
{
get { return value; }
}
public eRatValue Next
{
get { return next; }
}
public static implicit operator int(eRatValue eRatValue)
{
return eRatValue.Value;
}
}
#endregion
}
This allows you to do this:
这允许你这样做:
int something = eRat.A + eRat.B;
and this
这
eRat.eRatValue current = eRat.A;
while (current != null)
{
Console.WriteLine(current.Value);
current = current.Next;
}
You really should only be using enums when you can benefit from their type safety. If you're relying on them to represent a type, switch to constants or to classes.
只有当你能从它们的类型安全中获益时,你才应该使用枚举。如果您依赖它们来表示类型,请切换到常量或类。
EDIT
编辑
I would suggest you take a look at the MSDN page on Enumeration Design. The first best practice is:
我建议您看一下MSDN关于枚举设计的页面。第一个最佳实践是:
Do use an enumeration to strongly type parameters, properties, and return values that represent sets of values.
一定要对表示值集的强类型参数、属性和返回值使用枚举。
I try not to argue dogma, so I won't, but here's the problem you're going to face. Microsoft doesn't want you to do what you are trying to do. They explicitly ask you not to do what you are trying to do. The make it hard for you to do what you are trying to do. In order to accomplish what you are trying to do, you have to build utility code to force it to appear to work.
我尽量不去争辩教条,所以我不会,但这是你要面对的问题。微软不希望你做你想做的事情。他们明确地要求你不要做你想做的事。这让你很难做你想做的事情。为了完成您正在尝试做的事情,您必须构建实用程序代码来迫使它看起来工作。
You have called your solution elegant more than once, and it might be if enums were designed in a different way, but since enums are what they are, your solution isn't elegant. I think that chamber music is elegant, but if the musicians didn't have the proper instruments and had to play Vivaldi with sawblades and jugs, it would no longer be elegant, regardless of how capable they were as musicians, or how good the music was on paper.
您已经不止一次地将您的解决方案称作“优雅”了,而且如果enum是以不同的方式设计的,那么它可能是“优雅”的,但由于enum就是它们,因此您的解决方案并不优雅。我认为室内乐是优雅的,但是如果音乐家们没有合适的乐器,不得不用锯片和水壶演奏维瓦尔第,无论他们作为音乐家的能力有多强,或者音乐在纸上有多好,它都将不再优雅。
#5
7
Works up to "C" since there is no answer on what to return after "D".
因为在“D”之后返回的内容没有答案,所以答案是C。
[update1]: Updated according to Marc Gravell's suggestion.
[update2]: Updated according to how husayt's wanted - return "A" for the next value of "D".
[update1]:根据Marc Gravell的建议进行更新。[update2]:根据husayt的要求进行更新——返回“D”下一个值的“A”。
public class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Next enum of A = {0}", eRatEnumHelper.GetNextEnumValueOf(eRat.A));
Console.WriteLine("Next enum of B = {0}", eRatEnumHelper.GetNextEnumValueOf(eRat.B));
Console.WriteLine("Next enum of C = {0}", eRatEnumHelper.GetNextEnumValueOf(eRat.C));
}
}
public enum eRat { A = 0, B = 3, C = 5, D = 8 };
public class eRatEnumHelper
{
public static eRat GetNextEnumValueOf(eRat value)
{
return (from eRat val in Enum.GetValues(typeof (eRat))
where val > value
orderby val
select val).DefaultIfEmpty().First();
}
}
Result
结果
Next enum of A = B
Next enum of B = C
Next enum of C = D
Next enum of D = A下一个enum of A = B,下一个enum of B = C,下一个enum of C = D,下一个enum of D = A
#6
4
Judging from your description, you don't really want an enum. You're stretching enum beyond its capabilities. Why not create a custom class that exposes the values you need as properties, while keeping them in OrderedDictionary. Then getting a next/previous one would be trivial. --update
从你的描述来看,你并不是真的想要一个enum。你在伸展压力腔超出它的能力。为什么不创建一个自定义类来公开您需要的值作为属性,同时将它们保存在OrderedDictionary中呢?然后得到下一个/之前的一个是无关紧要的。- - -更新
If you want to enumerate differently on the collection based in the context, make that explicit part of your design. Encapsulate the items within a class, and have few methods each returning IEnumerable where, T is your desired type.
如果您希望在基于上下文的集合上以不同的方式枚举,请将该显式部分作为设计的一部分。将项封装在一个类中,并且有很少的方法每个返回IEnumerable,其中T是您需要的类型。
For example
例如
IEnumerable<Foo> GetFoosByBar()
IEnumerable<Foo> GetFoosByBaz()
etc...
等等……
#7
3
Are you locked into using an enum by something that you have no control over?
你是否被一些你无法控制的东西束缚在使用enum上?
If you're not, I'd suggest using an alternative, probably Dictionary<string, int> rat;
如果你不是,我建议你使用另一种,可能是字典
If you create a Dictionary
and you populate it with your data, enumerating over it is somewhat simpler. Also, it's a clearer mapping of intent-- you're mapping numbers to strings with this enum and you're trying to leverage that mapping.
如果创建一个字典并使用数据填充它,那么对它进行枚举就比较简单。此外,它是一种更清晰的意图映射——您正在用这个enum将数字映射到字符串,并试图利用这个映射。
If you must use the enum, I'd suggest something else:
如果你一定要使用enum,我可以提出其他建议:
var rats = new List<eRat>() {eRat.A, eRat.B, eRat.C, eRat.D};
As long as you're adding the values in-order and you keep it in sync, you greatly simplify the act of retrieving the next eRat.
只要将值按顺序添加并保持同步,就可以大大简化检索下一个eRat的行为。
#8
3
You could simplify it and generalize it some:
你可以化简一下,归纳一下:
static Enum GetNextValue(Enum e){
Array all = Enum.GetValues(e.GetType());
int i = Array.IndexOf(all, e);
if(i < 0)
throw new InvalidEnumArgumentException();
if(i == all.Length - 1)
throw new ArgumentException("No more values", "e");
return (Enum)all.GetValue(i + 1);
}
EDIT: Note that if your enum contains duplicate values (synonymous entries), then this (or any other technique listed here) will fail, given one of those values. For instance:
编辑:注意,如果您的枚举包含重复值(同义项),那么如果给定这些值中的一个,那么这个(或这里列出的任何其他技术)将失败。例如:
enum BRUSHSTYLE{
SOLID = 0,
HOLLOW = 1,
NULL = 1,
HATCHED = 2,
PATTERN = 3,
DIBPATTERN = 5,
DIBPATTERNPT = 6,
PATTERN8X8 = 7,
DIBPATTERN8X8 = 8
}
Given either BRUSHSTYLE.NULL
or BRUSHSTYLE.HOLLOW
, the return value would be BRUSHSTYLE.HOLLOW
.
鉴于BRUSHSTYLE。NULL或BRUSHSTYLE。空的,返回值将是笔触。空心。
<leppie>
< leppie >
Update: a generics version:
更新:一个泛型版本:
static T GetNextValue<T>(T e) { T[] all = (T[]) Enum.GetValues(typeof(T)); int i = Array.IndexOf(all, e); if (i < 0) throw new InvalidEnumArgumentException(); if (i == all.Length - 1) throw new ArgumentException("No more values", "e"); return all[i + 1]; }
</leppie>
< / leppie >
@leppie:
@leppie:
Your generic version allows one to accidentally pass a non-enum value, which will be caught only at run-time. I had originally written it as a generic, but when the compiler rejected where T : Enum
, I took it out and realized that I wasn't gaining much from generics anyway. The only real drawback is that you have to cast the result back to your specific enum type.
您的通用版本允许您意外地传递一个非枚举值,这个值只在运行时被捕获。我最初把它写成泛型,但是当编译器拒绝了T: Enum时,我把它拿了出来,并意识到我并没有从泛型中得到什么。惟一真正的缺点是必须将结果返回到特定的enum类型。
#9
3
For simple solution, you might just extract array from enum.
对于简单的解决方案,您可以从enum提取数组。
eRat[] list = (eRat[])Enum.GetValues(typeof(eRat));
Then you can enumerate
然后你可以列举
foreach (eRat item in list)
//Do something
Or find next item
或者找到下一个项目
int index = Array.IndexOf<eRat>(list, eRat.B);
eRat nextItem = list[index + 1];
Storing the array is better than extracting from enum each time you want next value.
存储数组比在每次需要下一个值时从enum中提取要好。
But if you want more beautiful solution, create the class.
但如果您想要更漂亮的解决方案,请创建类。
public class EnumEnumerator<T> : IEnumerator<T>, IEnumerable<T> {
int _index;
T[] _list;
public EnumEnumerator() {
if (!typeof(T).IsEnum)
throw new NotSupportedException();
_list = (T[])Enum.GetValues(typeof(T));
}
public T Current {
get { return _list[_index]; }
}
public bool MoveNext() {
if (_index + 1 >= _list.Length)
return false;
_index++;
return true;
}
public bool MovePrevious() {
if (_index <= 0)
return false;
_index--;
return true;
}
public bool Seek(T item) {
int i = Array.IndexOf<T>(_list, item);
if (i >= 0) {
_index = i;
return true;
} else
return false;
}
public void Reset() {
_index = 0;
}
public IEnumerator<T> GetEnumerator() {
return ((IEnumerable<T>)_list).GetEnumerator();
}
void IDisposable.Dispose() { }
object System.Collections.IEnumerator.Current {
get { return Current; }
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
return _list.GetEnumerator();
}
}
Instantiate
实例化
var eRatEnum = new EnumEnumerator<eRat>();
Iterate
迭代
foreach (eRat item in eRatEnum)
//Do something
MoveNext
MoveNext
eRatEnum.Seek(eRat.B);
eRatEnum.MoveNext();
eRat nextItem = eRatEnum.Current;
#10
2
Hope this part of my code helps you:
希望我的这部分代码能对您有所帮助:
public enum EGroupedBy
{
Type,
InterfaceAndType,
Alpha,
_max
}
private void _btnViewUnit_Click(object sender, EventArgs e)
{
int i = (int)GroupedBy;
i = (i + 1) % (int)EGroupedBy._max;
GroupedBy = (EGroupedBy) i;
RefreshUnit();
}
#11
1
I can think of 2 things:
我能想到两件事:
- eRat.B+3
- eRat.B + 3
- Enum.Parse(typeof(((int)eRat.B)+3)
- Enum.Parse(typeof(((int)eRat.B)+ 3)
#12
1
var next = (eRat)((int)someRat + 3);
var next = (eRat)(int)someRat + 3;
#13
1
I'm using this, perfect for my.
我在用这个,非常适合我的。
//===================================================================================
// NEXT VALUE IN ENUM
// ex: E_CamModes eNew = kGlobalsVars.eGetNextValue< E_CamModes >( geCmMode );
public static T eGetNextValue< T >( T eIn ){
T[] aiAllValues = ( T[] ) Enum.GetValues( typeof( T ));
int iVal = System.Array.IndexOf( aiAllValues, eIn );
return aiAllValues[ ( iVal + 1 ) % aiAllValues.Length ];
}
#14
1
Old post, but I have an alternative solution
以前的帖子,但是我有另外的解决办法
//Next with looping
public static Enum Next(this Enum input)
{
Array Arr = Enum.GetValues(input.GetType());
int j = Array.IndexOf(Arr, input) + 1;
return (Arr.Length == j) ? (Enum)Arr.GetValue(0) : (Enum)Arr.GetValue(j);
}
//Previous with looping
public static Enum Prev(this Enum input)
{
Array Arr = Enum.GetValues(input.GetType());
int j = Array.IndexOf(Arr, input) - 1;
return (j == -1) ? (Enum)Arr.GetValue(Arr.Length -1) : (Enum)Arr.GetValue(j);
}
And when you need to use it, just do a cast
当你需要使用它的时候,就做一个石膏模型
BootstrapThemeEnum theme = BootstrapThemeEnum.Info;
var next = (BootstrapThemeEnum)theme.Next();
my enum
我的枚举
public enum BootstrapThemeEnum
{
[Description("white")]
White = 0,
[Description("default")]
Default = 1,
[Description("info")]
Info = 2,
[Description("primary")]
Primary = 3,
[Description("success")]
Success = 4,
[Description("warning")]
Warning = 5,
[Description("danger")]
Danger = 6,
[Description("inverse")]
Inverse = 7
}
#15
0
I would go with Sung Meister's answer but here is an alternative:
我同意宋迈斯特的回答,但这里有一个选择:
MyEnum initial = MyEnum.B, next;
for (int i = ((int) initial) + 1, i < int.MaxValue; i++)
{
if (Enum.IsDefined(typeof(MyEnum), (MyEnum) i))
{
next = (MyEnum) i;
break;
}
}
Note: many assumptions assumed :)
注:假设有很多假设:)
#16
0
Seems like an abuse of the enum class to me - but this would do it (assuming that calling Next on the last value would cause wrap-around):
看起来像对我的枚举类的滥用,但这将会这样做(假设在最后一个值上调用Next会导致wrap-around):
public static eRat Next(this eRat target)
{
var nextValueQuery = Enum.GetValues(typeof(eRat)).Cast<eRat>().SkipWhile(e => e != target).Skip(1);
if (nextValueQuery.Count() != 0)
{
return (eRat)nextValueQuery.First();
}
else
{
return eRat.A;
}
}
And this would give you the previous value on the same basis:
这就得到了之前的值
public static eRat Previous(this eRat target)
{
var nextValueQuery = Enum.GetValues(typeof(eRat)).Cast<eRat>().Reverse().SkipWhile(e => e != target).Skip(1);
if (nextValueQuery.Count() != 0)
{
return (eRat)nextValueQuery.First();
}
else
{
return eRat.D;
}
}
#17
0
From comments I had many question like: "Why would you ever want to use enum in this way." Since so many of you asked, let me give you my use case and see if you agree then:
从评论中,我提出了许多问题,比如:“为什么您要以这种方式使用enum ?”既然你们中有这么多人问过这个问题,让我把我的用例给你们看看你们是否同意:
I have a fixed array of items int[n]
. Depending on the situation I want to enumerate through this array differently. So i defined:
我有一个固定的项目数组int[n]。根据不同的情况,我希望通过这个数组以不同的方式枚举。所以我的定义:
int[] Arr= {1,2,34,5,6,78,9,90,30};
enum eRat1 { A = 0, B=3, C=5, D=8 };
enum eRat2 { A, AA,AAA,B,BB,C,C,CC,D };
void walk(Type enumType)
{
foreach (Type t in Enum.GetValues(enumType))
{
write(t.ToString() + " = " + Arr[(int)t)];
}
}
and call walk(typeof(eRAt1))
or walk(typeof(eRAt2))
调用walk(typeof(eRAt1)或walk(typeof(eRAt2))
then i get required output
然后得到所需的输出
1) walk(typeof(eRAt1))
1)走(typeof(eRAt1))
A = 1
B = 5
C = 78
D = 30
2) walk(typeof(eRAt2))
2)走(typeof(eRAt2))
A = 1
AA = 2
AAA = 34
B = 5
BB = 6
C = 78
CC = 90
D = 30
This is very simplified. But i hope, this explains. There are some other advantages to this, as having enum.toString(). So basically i use enums as indexers.
这是非常简单。但我希望,这解释了。还有一些其他的优点,如枚举. tostring()。基本上我用枚举作为索引器。
So using the solution I can do something like this now.
用这个解,我现在可以这样做了。
In sequence eRat1 next value to B is C, but in eRat2 it is BB. So depending on which sequence I am interested in, I can do e.next and depending on enumType I will either get C or BB. How would one achieve that with dictionaries?
在序列eRat1中,B的下一个值是C,但在eRat2中,它是BB。根据我感兴趣的序列,我可以做e。接下来,根据枚举类型,我将得到C或BB。如何用字典来实现这一点呢?
I think this a rather elegant use of enums.
我认为这是对枚举的优雅使用。
#18
0
I'm using this here:
我用这个:
public MyEnum getNext() {
return this.ordinal() < MyEnum.values().length - 1 ?
MyEnum.values()[this.ordinal() + 1] :
MyEnum.values()[0];
}
#19
0
LINQ solution that does not break on last element but continues at the default again:
LINQ解决方案没有中断最后一个元素,但仍然在默认情况下继续:
var nextValue = Enum.GetValues(typeof(EnumT)).Cast<EnumT>().Concat(new[]{default(EnumT)}).SkipWhile(_ => _ != value).Skip(1).First();
#20
0
There is a very simple solution (if you can change your integer values) that is specifically designed to work with numbers. The fact that your number is an enum
, isn't a problem. It is still the integer
(or whatever underlying number type you assign). Enum
just adds the complexity of a cast requirement.
有一个非常简单的解决方案(如果您可以更改整数值),它是专门设计用来处理数字的。你的号码是enum,这不是问题。它仍然是整数(或您指定的任何基础数字类型)。Enum只是增加了一个cast需求的复杂性。
Assume your enum
is defined like this:
假设您的enum的定义如下:
public enum ItemStatus
{
New = 0,
Draft = 1,
Received = 2,
Review = 4,
Rejected = 8,
Approved = 16
}
ItemStatus myStatus = ItemStatus.Draft;
Use bitwise operations on the Enum
. For Example:
在枚举中使用位操作。例如:
myStatus = (ItemStatus)(((int)myStatus) << 1)
The result is of myStatus is: ItemStatus.Received.
结果是myStatus为:ItemStatus.Received。
You can also go backwards down the Enum
by changing the bitwise operator from <<
to >>
.
您还可以通过将位运算符从<< < <转换为> >来向下循环。
myStatus = (ItemStatus)(((int)myStatus) << 1)
The result is of myStatus is: ItemStatus.New.
结果是myStatus为:ItemStatus.New。
You should always add code to test for an "out of bounds" situation in both directions.
您应该始终在两个方向上为“越界”情况添加代码进行测试。
You can understand more about bitwise operations here: http://code.tutsplus.com/articles/understanding-bitwise-operators--active-11301
您可以在这里了解更多关于位操作的信息:http://code.tutsplus.com/articles/understand -bitwise-operators-- active11301
#1
41
Thanks to everybody for your answers and feedback. I was surprised to get so many of them. Looking at them and using some of the ideas, I came up with this solution, which works best for me:
谢谢大家的回答和反馈。我很惊讶能得到这么多。看看他们,并运用其中的一些想法,我想到了这个对我最有效的解决方案:
public static class Extensions
{
public static T Next<T>(this T src) where T : struct
{
if (!typeof(T).IsEnum) throw new ArgumentException(String.Format("Argumnent {0} is not an Enum", typeof(T).FullName));
T[] Arr = (T[])Enum.GetValues(src.GetType());
int j = Array.IndexOf<T>(Arr, src) + 1;
return (Arr.Length==j) ? Arr[0] : Arr[j];
}
}
The beaty of this approach, that it is simple and universal to use. Implemented as generic extension method, you can call it on any enum this way:
这种方法的优点是,使用起来简单而通用。作为通用扩展方法实现,您可以在任何enum上以以下方式调用:
return eRat.B.Next();
Notice, I am using generalized extension method, thus I don't need to specify type upon call, just .Next()
.
注意,我使用的是通用扩展方法,因此不需要在调用时指定类型,只需. next()。
Thanks again.
再次感谢。
#2
36
Probably a bit overkill, but:
可能有点过头了,但是:
eRat value = eRat.B;
eRat nextValue = Enum.GetValues(typeof(eRat)).Cast<eRat>()
.SkipWhile(e => e != value).Skip(1).First();
or if you want the first that is numerically bigger:
或者如果你想要第一个数字更大:
eRat nextValue = Enum.GetValues(typeof(eRat)).Cast<eRat>()
.First(e => (int)e > (int)value);
or for the next bigger numerically (doing the sort ourselves):
或者对于下一个较大的数字(自己做排序):
eRat nextValue = Enum.GetValues(typeof(eRat)).Cast<eRat>()
.Where(e => (int)e > (int)value).OrderBy(e => e).First();
Hey, with LINQ as your hammer, the world is full of nails ;-p
嘿,LINQ作为你的锤子,世界充满了钉子;-p
#3
23
Do you really need to generalize this problem? Can you just do this instead?
你真的需要概括这个问题吗?你可以这样做吗?
public void SomeMethod(MyEnum myEnum)
{
MyEnum? nextMyEnum = myEnum.Next();
if (nextMyEnum.HasValue)
{
...
}
}
public static MyEnum? Next(this MyEnum myEnum)
{
switch (myEnum)
{
case MyEnum.A:
return MyEnum.B;
case MyEnum.B:
return MyEnum.C;
case MyEnum.C:
return MyEnum.D;
default:
return null;
}
}
#4
12
The problem you're dealing with is because you're trying to get an enum to do something it shouldn't. They're supposed to be type safe. Assigning integral values to an enum is allowed so that you can combine them, but if you want them to represent integral values, use classes or structs. Here's a possible alternative:
您正在处理的问题是,因为您试图获得一个enum来执行它不应该执行的操作。它们应该是类型安全的。为enum分配整数值是允许的,以便您可以组合它们,但是如果您希望它们表示整数值,请使用类或结构。这里有一个可能的替代方法:
public static class eRat
{
public static readonly eRatValue A;
public static readonly eRatValue B;
public static readonly eRatValue C;
public static readonly eRatValue D;
static eRat()
{
D = new eRatValue(8, null);
C = new eRatValue(5, D);
B = new eRatValue(3, C);
A = new eRatValue(0, B);
}
#region Nested type: ERatValue
public class eRatValue
{
private readonly eRatValue next;
private readonly int value;
public eRatValue(int value, eRatValue next)
{
this.value = value;
this.next = next;
}
public int Value
{
get { return value; }
}
public eRatValue Next
{
get { return next; }
}
public static implicit operator int(eRatValue eRatValue)
{
return eRatValue.Value;
}
}
#endregion
}
This allows you to do this:
这允许你这样做:
int something = eRat.A + eRat.B;
and this
这
eRat.eRatValue current = eRat.A;
while (current != null)
{
Console.WriteLine(current.Value);
current = current.Next;
}
You really should only be using enums when you can benefit from their type safety. If you're relying on them to represent a type, switch to constants or to classes.
只有当你能从它们的类型安全中获益时,你才应该使用枚举。如果您依赖它们来表示类型,请切换到常量或类。
EDIT
编辑
I would suggest you take a look at the MSDN page on Enumeration Design. The first best practice is:
我建议您看一下MSDN关于枚举设计的页面。第一个最佳实践是:
Do use an enumeration to strongly type parameters, properties, and return values that represent sets of values.
一定要对表示值集的强类型参数、属性和返回值使用枚举。
I try not to argue dogma, so I won't, but here's the problem you're going to face. Microsoft doesn't want you to do what you are trying to do. They explicitly ask you not to do what you are trying to do. The make it hard for you to do what you are trying to do. In order to accomplish what you are trying to do, you have to build utility code to force it to appear to work.
我尽量不去争辩教条,所以我不会,但这是你要面对的问题。微软不希望你做你想做的事情。他们明确地要求你不要做你想做的事。这让你很难做你想做的事情。为了完成您正在尝试做的事情,您必须构建实用程序代码来迫使它看起来工作。
You have called your solution elegant more than once, and it might be if enums were designed in a different way, but since enums are what they are, your solution isn't elegant. I think that chamber music is elegant, but if the musicians didn't have the proper instruments and had to play Vivaldi with sawblades and jugs, it would no longer be elegant, regardless of how capable they were as musicians, or how good the music was on paper.
您已经不止一次地将您的解决方案称作“优雅”了,而且如果enum是以不同的方式设计的,那么它可能是“优雅”的,但由于enum就是它们,因此您的解决方案并不优雅。我认为室内乐是优雅的,但是如果音乐家们没有合适的乐器,不得不用锯片和水壶演奏维瓦尔第,无论他们作为音乐家的能力有多强,或者音乐在纸上有多好,它都将不再优雅。
#5
7
Works up to "C" since there is no answer on what to return after "D".
因为在“D”之后返回的内容没有答案,所以答案是C。
[update1]: Updated according to Marc Gravell's suggestion.
[update2]: Updated according to how husayt's wanted - return "A" for the next value of "D".
[update1]:根据Marc Gravell的建议进行更新。[update2]:根据husayt的要求进行更新——返回“D”下一个值的“A”。
public class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Next enum of A = {0}", eRatEnumHelper.GetNextEnumValueOf(eRat.A));
Console.WriteLine("Next enum of B = {0}", eRatEnumHelper.GetNextEnumValueOf(eRat.B));
Console.WriteLine("Next enum of C = {0}", eRatEnumHelper.GetNextEnumValueOf(eRat.C));
}
}
public enum eRat { A = 0, B = 3, C = 5, D = 8 };
public class eRatEnumHelper
{
public static eRat GetNextEnumValueOf(eRat value)
{
return (from eRat val in Enum.GetValues(typeof (eRat))
where val > value
orderby val
select val).DefaultIfEmpty().First();
}
}
Result
结果
Next enum of A = B
Next enum of B = C
Next enum of C = D
Next enum of D = A下一个enum of A = B,下一个enum of B = C,下一个enum of C = D,下一个enum of D = A
#6
4
Judging from your description, you don't really want an enum. You're stretching enum beyond its capabilities. Why not create a custom class that exposes the values you need as properties, while keeping them in OrderedDictionary. Then getting a next/previous one would be trivial. --update
从你的描述来看,你并不是真的想要一个enum。你在伸展压力腔超出它的能力。为什么不创建一个自定义类来公开您需要的值作为属性,同时将它们保存在OrderedDictionary中呢?然后得到下一个/之前的一个是无关紧要的。- - -更新
If you want to enumerate differently on the collection based in the context, make that explicit part of your design. Encapsulate the items within a class, and have few methods each returning IEnumerable where, T is your desired type.
如果您希望在基于上下文的集合上以不同的方式枚举,请将该显式部分作为设计的一部分。将项封装在一个类中,并且有很少的方法每个返回IEnumerable,其中T是您需要的类型。
For example
例如
IEnumerable<Foo> GetFoosByBar()
IEnumerable<Foo> GetFoosByBaz()
etc...
等等……
#7
3
Are you locked into using an enum by something that you have no control over?
你是否被一些你无法控制的东西束缚在使用enum上?
If you're not, I'd suggest using an alternative, probably Dictionary<string, int> rat;
如果你不是,我建议你使用另一种,可能是字典
If you create a Dictionary
and you populate it with your data, enumerating over it is somewhat simpler. Also, it's a clearer mapping of intent-- you're mapping numbers to strings with this enum and you're trying to leverage that mapping.
如果创建一个字典并使用数据填充它,那么对它进行枚举就比较简单。此外,它是一种更清晰的意图映射——您正在用这个enum将数字映射到字符串,并试图利用这个映射。
If you must use the enum, I'd suggest something else:
如果你一定要使用enum,我可以提出其他建议:
var rats = new List<eRat>() {eRat.A, eRat.B, eRat.C, eRat.D};
As long as you're adding the values in-order and you keep it in sync, you greatly simplify the act of retrieving the next eRat.
只要将值按顺序添加并保持同步,就可以大大简化检索下一个eRat的行为。
#8
3
You could simplify it and generalize it some:
你可以化简一下,归纳一下:
static Enum GetNextValue(Enum e){
Array all = Enum.GetValues(e.GetType());
int i = Array.IndexOf(all, e);
if(i < 0)
throw new InvalidEnumArgumentException();
if(i == all.Length - 1)
throw new ArgumentException("No more values", "e");
return (Enum)all.GetValue(i + 1);
}
EDIT: Note that if your enum contains duplicate values (synonymous entries), then this (or any other technique listed here) will fail, given one of those values. For instance:
编辑:注意,如果您的枚举包含重复值(同义项),那么如果给定这些值中的一个,那么这个(或这里列出的任何其他技术)将失败。例如:
enum BRUSHSTYLE{
SOLID = 0,
HOLLOW = 1,
NULL = 1,
HATCHED = 2,
PATTERN = 3,
DIBPATTERN = 5,
DIBPATTERNPT = 6,
PATTERN8X8 = 7,
DIBPATTERN8X8 = 8
}
Given either BRUSHSTYLE.NULL
or BRUSHSTYLE.HOLLOW
, the return value would be BRUSHSTYLE.HOLLOW
.
鉴于BRUSHSTYLE。NULL或BRUSHSTYLE。空的,返回值将是笔触。空心。
<leppie>
< leppie >
Update: a generics version:
更新:一个泛型版本:
static T GetNextValue<T>(T e) { T[] all = (T[]) Enum.GetValues(typeof(T)); int i = Array.IndexOf(all, e); if (i < 0) throw new InvalidEnumArgumentException(); if (i == all.Length - 1) throw new ArgumentException("No more values", "e"); return all[i + 1]; }
</leppie>
< / leppie >
@leppie:
@leppie:
Your generic version allows one to accidentally pass a non-enum value, which will be caught only at run-time. I had originally written it as a generic, but when the compiler rejected where T : Enum
, I took it out and realized that I wasn't gaining much from generics anyway. The only real drawback is that you have to cast the result back to your specific enum type.
您的通用版本允许您意外地传递一个非枚举值,这个值只在运行时被捕获。我最初把它写成泛型,但是当编译器拒绝了T: Enum时,我把它拿了出来,并意识到我并没有从泛型中得到什么。惟一真正的缺点是必须将结果返回到特定的enum类型。
#9
3
For simple solution, you might just extract array from enum.
对于简单的解决方案,您可以从enum提取数组。
eRat[] list = (eRat[])Enum.GetValues(typeof(eRat));
Then you can enumerate
然后你可以列举
foreach (eRat item in list)
//Do something
Or find next item
或者找到下一个项目
int index = Array.IndexOf<eRat>(list, eRat.B);
eRat nextItem = list[index + 1];
Storing the array is better than extracting from enum each time you want next value.
存储数组比在每次需要下一个值时从enum中提取要好。
But if you want more beautiful solution, create the class.
但如果您想要更漂亮的解决方案,请创建类。
public class EnumEnumerator<T> : IEnumerator<T>, IEnumerable<T> {
int _index;
T[] _list;
public EnumEnumerator() {
if (!typeof(T).IsEnum)
throw new NotSupportedException();
_list = (T[])Enum.GetValues(typeof(T));
}
public T Current {
get { return _list[_index]; }
}
public bool MoveNext() {
if (_index + 1 >= _list.Length)
return false;
_index++;
return true;
}
public bool MovePrevious() {
if (_index <= 0)
return false;
_index--;
return true;
}
public bool Seek(T item) {
int i = Array.IndexOf<T>(_list, item);
if (i >= 0) {
_index = i;
return true;
} else
return false;
}
public void Reset() {
_index = 0;
}
public IEnumerator<T> GetEnumerator() {
return ((IEnumerable<T>)_list).GetEnumerator();
}
void IDisposable.Dispose() { }
object System.Collections.IEnumerator.Current {
get { return Current; }
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
return _list.GetEnumerator();
}
}
Instantiate
实例化
var eRatEnum = new EnumEnumerator<eRat>();
Iterate
迭代
foreach (eRat item in eRatEnum)
//Do something
MoveNext
MoveNext
eRatEnum.Seek(eRat.B);
eRatEnum.MoveNext();
eRat nextItem = eRatEnum.Current;
#10
2
Hope this part of my code helps you:
希望我的这部分代码能对您有所帮助:
public enum EGroupedBy
{
Type,
InterfaceAndType,
Alpha,
_max
}
private void _btnViewUnit_Click(object sender, EventArgs e)
{
int i = (int)GroupedBy;
i = (i + 1) % (int)EGroupedBy._max;
GroupedBy = (EGroupedBy) i;
RefreshUnit();
}
#11
1
I can think of 2 things:
我能想到两件事:
- eRat.B+3
- eRat.B + 3
- Enum.Parse(typeof(((int)eRat.B)+3)
- Enum.Parse(typeof(((int)eRat.B)+ 3)
#12
1
var next = (eRat)((int)someRat + 3);
var next = (eRat)(int)someRat + 3;
#13
1
I'm using this, perfect for my.
我在用这个,非常适合我的。
//===================================================================================
// NEXT VALUE IN ENUM
// ex: E_CamModes eNew = kGlobalsVars.eGetNextValue< E_CamModes >( geCmMode );
public static T eGetNextValue< T >( T eIn ){
T[] aiAllValues = ( T[] ) Enum.GetValues( typeof( T ));
int iVal = System.Array.IndexOf( aiAllValues, eIn );
return aiAllValues[ ( iVal + 1 ) % aiAllValues.Length ];
}
#14
1
Old post, but I have an alternative solution
以前的帖子,但是我有另外的解决办法
//Next with looping
public static Enum Next(this Enum input)
{
Array Arr = Enum.GetValues(input.GetType());
int j = Array.IndexOf(Arr, input) + 1;
return (Arr.Length == j) ? (Enum)Arr.GetValue(0) : (Enum)Arr.GetValue(j);
}
//Previous with looping
public static Enum Prev(this Enum input)
{
Array Arr = Enum.GetValues(input.GetType());
int j = Array.IndexOf(Arr, input) - 1;
return (j == -1) ? (Enum)Arr.GetValue(Arr.Length -1) : (Enum)Arr.GetValue(j);
}
And when you need to use it, just do a cast
当你需要使用它的时候,就做一个石膏模型
BootstrapThemeEnum theme = BootstrapThemeEnum.Info;
var next = (BootstrapThemeEnum)theme.Next();
my enum
我的枚举
public enum BootstrapThemeEnum
{
[Description("white")]
White = 0,
[Description("default")]
Default = 1,
[Description("info")]
Info = 2,
[Description("primary")]
Primary = 3,
[Description("success")]
Success = 4,
[Description("warning")]
Warning = 5,
[Description("danger")]
Danger = 6,
[Description("inverse")]
Inverse = 7
}
#15
0
I would go with Sung Meister's answer but here is an alternative:
我同意宋迈斯特的回答,但这里有一个选择:
MyEnum initial = MyEnum.B, next;
for (int i = ((int) initial) + 1, i < int.MaxValue; i++)
{
if (Enum.IsDefined(typeof(MyEnum), (MyEnum) i))
{
next = (MyEnum) i;
break;
}
}
Note: many assumptions assumed :)
注:假设有很多假设:)
#16
0
Seems like an abuse of the enum class to me - but this would do it (assuming that calling Next on the last value would cause wrap-around):
看起来像对我的枚举类的滥用,但这将会这样做(假设在最后一个值上调用Next会导致wrap-around):
public static eRat Next(this eRat target)
{
var nextValueQuery = Enum.GetValues(typeof(eRat)).Cast<eRat>().SkipWhile(e => e != target).Skip(1);
if (nextValueQuery.Count() != 0)
{
return (eRat)nextValueQuery.First();
}
else
{
return eRat.A;
}
}
And this would give you the previous value on the same basis:
这就得到了之前的值
public static eRat Previous(this eRat target)
{
var nextValueQuery = Enum.GetValues(typeof(eRat)).Cast<eRat>().Reverse().SkipWhile(e => e != target).Skip(1);
if (nextValueQuery.Count() != 0)
{
return (eRat)nextValueQuery.First();
}
else
{
return eRat.D;
}
}
#17
0
From comments I had many question like: "Why would you ever want to use enum in this way." Since so many of you asked, let me give you my use case and see if you agree then:
从评论中,我提出了许多问题,比如:“为什么您要以这种方式使用enum ?”既然你们中有这么多人问过这个问题,让我把我的用例给你们看看你们是否同意:
I have a fixed array of items int[n]
. Depending on the situation I want to enumerate through this array differently. So i defined:
我有一个固定的项目数组int[n]。根据不同的情况,我希望通过这个数组以不同的方式枚举。所以我的定义:
int[] Arr= {1,2,34,5,6,78,9,90,30};
enum eRat1 { A = 0, B=3, C=5, D=8 };
enum eRat2 { A, AA,AAA,B,BB,C,C,CC,D };
void walk(Type enumType)
{
foreach (Type t in Enum.GetValues(enumType))
{
write(t.ToString() + " = " + Arr[(int)t)];
}
}
and call walk(typeof(eRAt1))
or walk(typeof(eRAt2))
调用walk(typeof(eRAt1)或walk(typeof(eRAt2))
then i get required output
然后得到所需的输出
1) walk(typeof(eRAt1))
1)走(typeof(eRAt1))
A = 1
B = 5
C = 78
D = 30
2) walk(typeof(eRAt2))
2)走(typeof(eRAt2))
A = 1
AA = 2
AAA = 34
B = 5
BB = 6
C = 78
CC = 90
D = 30
This is very simplified. But i hope, this explains. There are some other advantages to this, as having enum.toString(). So basically i use enums as indexers.
这是非常简单。但我希望,这解释了。还有一些其他的优点,如枚举. tostring()。基本上我用枚举作为索引器。
So using the solution I can do something like this now.
用这个解,我现在可以这样做了。
In sequence eRat1 next value to B is C, but in eRat2 it is BB. So depending on which sequence I am interested in, I can do e.next and depending on enumType I will either get C or BB. How would one achieve that with dictionaries?
在序列eRat1中,B的下一个值是C,但在eRat2中,它是BB。根据我感兴趣的序列,我可以做e。接下来,根据枚举类型,我将得到C或BB。如何用字典来实现这一点呢?
I think this a rather elegant use of enums.
我认为这是对枚举的优雅使用。
#18
0
I'm using this here:
我用这个:
public MyEnum getNext() {
return this.ordinal() < MyEnum.values().length - 1 ?
MyEnum.values()[this.ordinal() + 1] :
MyEnum.values()[0];
}
#19
0
LINQ solution that does not break on last element but continues at the default again:
LINQ解决方案没有中断最后一个元素,但仍然在默认情况下继续:
var nextValue = Enum.GetValues(typeof(EnumT)).Cast<EnumT>().Concat(new[]{default(EnumT)}).SkipWhile(_ => _ != value).Skip(1).First();
#20
0
There is a very simple solution (if you can change your integer values) that is specifically designed to work with numbers. The fact that your number is an enum
, isn't a problem. It is still the integer
(or whatever underlying number type you assign). Enum
just adds the complexity of a cast requirement.
有一个非常简单的解决方案(如果您可以更改整数值),它是专门设计用来处理数字的。你的号码是enum,这不是问题。它仍然是整数(或您指定的任何基础数字类型)。Enum只是增加了一个cast需求的复杂性。
Assume your enum
is defined like this:
假设您的enum的定义如下:
public enum ItemStatus
{
New = 0,
Draft = 1,
Received = 2,
Review = 4,
Rejected = 8,
Approved = 16
}
ItemStatus myStatus = ItemStatus.Draft;
Use bitwise operations on the Enum
. For Example:
在枚举中使用位操作。例如:
myStatus = (ItemStatus)(((int)myStatus) << 1)
The result is of myStatus is: ItemStatus.Received.
结果是myStatus为:ItemStatus.Received。
You can also go backwards down the Enum
by changing the bitwise operator from <<
to >>
.
您还可以通过将位运算符从<< < <转换为> >来向下循环。
myStatus = (ItemStatus)(((int)myStatus) << 1)
The result is of myStatus is: ItemStatus.New.
结果是myStatus为:ItemStatus.New。
You should always add code to test for an "out of bounds" situation in both directions.
您应该始终在两个方向上为“越界”情况添加代码进行测试。
You can understand more about bitwise operations here: http://code.tutsplus.com/articles/understanding-bitwise-operators--active-11301
您可以在这里了解更多关于位操作的信息:http://code.tutsplus.com/articles/understand -bitwise-operators-- active11301