C# 当我尝试使用或返回枚举值时,我可以避免强制转换它吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/577946/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Can I avoid casting an enum value when I try to use or return it?
提问by Mark Carpenter
If I have the following enum:
如果我有以下枚举:
public enum ReturnValue{
Success = 0,
FailReason1 = 1,
FailReason2 = 2
//Etc...
}
Can I avoid casting when I return, like this:
我回来时可以避免投射吗,像这样:
public static int main(string[] args){
return (int)ReturnValue.Success;
}
If not, why isn't an enum value treated as an int by default?
如果不是,为什么默认情况下不将枚举值视为 int?
采纳答案by Michael Meadows
enums are supposed to be type safe. I think they didn't make them implicitly castable to discourage other uses. Although the framework allows you to assign a constant value to them, you should reconsider your intent. If you primarily use the enum for storing constant values, consider using a static class:
枚举应该是类型安全的。我认为他们并没有让它们隐式可铸造以阻止其他用途。尽管该框架允许您为它们分配一个常量值,但您应该重新考虑您的意图。如果您主要使用枚举来存储常量值,请考虑使用静态类:
public static class ReturnValue
{
public const int Success = 0;
public const int FailReason1 = 1;
public const int FailReason2 = 2;
//Etc...
}
That lets you do this.
这可以让你做到这一点。
public static int main(string[] args){
return ReturnValue.Success;
}
EDIT
编辑
When you dowant to provide values to an enum is when you want to combine them. See the below example:
当您确实想为枚举提供值时,就是将它们组合起来的时候。请参阅以下示例:
[Flags] // indicates bitwise operations occur on this enum
public enum DaysOfWeek : byte // byte type to limit size
{
Sunday = 1,
Monday = 2,
Tuesday = 4,
Wednesday = 8,
Thursday = 16,
Friday = 32,
Saturday = 64,
Weekend = Sunday | Saturday,
Weekdays = Monday | Tuesday | Wednesday | Thursday | Friday
}
This enum can then be consumed by using bitwise math. See the below example for some applications.
然后可以通过使用按位数学来使用该枚举。有关某些应用程序,请参阅以下示例。
public static class DaysOfWeekEvaluator
{
public static bool IsWeekends(DaysOfWeek days)
{
return (days & DaysOfWeek.Weekend) == DaysOfWeek.Weekend;
}
public static bool IsAllWeekdays(DaysOfWeek days)
{
return (days & DaysOfWeek.Weekdays) == DaysOfWeek.Weekdays;
}
public static bool HasWeekdays(DaysOfWeek days)
{
return ((int) (days & DaysOfWeek.Weekdays)) > 0;
}
public static bool HasWeekendDays(DaysOfWeek days)
{
return ((int) (days & DaysOfWeek.Weekend)) > 0;
}
}
回答by Marc Gravell
Enums and ints are simply not implicitly castable as per the spec (except for the literal 0, which is allowed for comparison tests / assignments / etc). The explicit cast is all that is needed, though.
根据规范,枚举和整数不能隐式转换(文字 0 除外,它允许用于比较测试/赋值等)。不过,显式演员表就是所需要的。
回答by mqp
No, you can't avoid casting; as to why there's no implicit conversion, I don't know, but there's not.
不,你不能避免强制转换;至于为什么没有隐式转换,我不知道,但没有。
回答by tvanfosson
There is no implicit cast because the enum does not have to use int as the underlying type. If your enum used a uint as the underlying type, for instance, there is no implicit cast from uint to int.
没有隐式强制转换,因为枚举不必使用 int 作为基础类型。例如,如果您的枚举使用 uint 作为基础类型,则没有从 uint 到 int 的隐式转换。
回答by Mike
Strangely enough, this is not specific to the .NET Framework, but just to C#. As the other commenters have already pointed out, in C# this is basically a specification of the language. The same is not true in VB.NET.
奇怪的是,这并非特定于 .NET Framework,而仅适用于 C#。正如其他评论者已经指出的那样,在 C# 中,这基本上是语言的规范。在 VB.NET 中情况并非如此。
Check out the MSDN reference page for Enums in VB.NET. Note that you can specify the data type of an enumeration at Enum declaration time.
查看VB.NET 中 Enums的 MSDN 参考页面。请注意,您可以在 Enum 声明时指定枚举的数据类型。
That means, if you reallydon't want to litter your code with casts to (int), you could write your enumeration in VB.NET, declare it as an integer, then use that Enum from C#.
这意味着,如果您真的不想将代码转换为 (int),则可以在 VB.NET 中编写枚举,将其声明为整数,然后使用 C# 中的 Enum。
Remember how they told us computers would make our lives so much simpler? :)
还记得他们是如何告诉我们计算机会让我们的生活变得如此简单的吗?:)
回答by Cerebrus
You can ascribe this behaviour to the basic intention behind creating Enumerations... to create a set of named constants that can only have specified (or default) values depending on the underlying type.
您可以将此行为归因于创建枚举背后的基本意图...创建一组命名常量,这些常量只能根据基础类型指定(或默认)值。
There are two separate issues to consider, as related to your question:
与您的问题相关,有两个单独的问题需要考虑:
An
Enum
value cannot be treated as an int by default because then you would be able to provide anyinteger and there would be no compile time check to validate that the provided integer does in fact exist as a value in the Enumeration.Casting becomes necessary since you are trying to convert from the governing type (of type
YourCustomEnum
which derives from theSystem.Enum
class) to the underlying type, i.e.,int
orbyte
, etc.
一个
Enum
数值不能作为默认的int来处理,因为你将能够提供任何整数,就没有编译时检查,以验证所提供的整数事实上是存在的不作为枚举值。强制转换变得必要,因为您试图从控制类型(
YourCustomEnum
从System.Enum
类派生的类型)转换为基础类型,即,int
或byte
等。
回答by Triynko
The c# enum is useless.
c# 枚举没用。
You can avoid casting from your type AND constrain the values that can be explicitly cast to your type by making a sealed class, and providing implicit/explicit conversion operators.
您可以避免从您的类型进行强制转换,并通过创建密封类并提供隐式/显式转换运算符来限制可以显式转换为您的类型的值。
- Provide an implicit operator for converting from your type to a generic int so you don't have to cast.
- Provide an explicit operator for converting from an int to your type, which throws an error if the integer fails to meet the constraint, such as (int x) => (x >= 0 && x <= 2).
- 提供用于从您的类型转换为泛型 int 的隐式运算符,因此您不必进行强制转换。
- 提供用于从 int 转换为您的类型的显式运算符,如果整数不满足约束,则会引发错误,例如 (int x) => (x >= 0 && x <= 2)。
If using this technique, create a generic immutable base class such as ConstrainedNumber<T>
, which has a constructor that accepts a T value and delegate for the constraint: delegate bool NumberConstraint<T>(T value)
. The constructor should run the value through the constraint delegate, and throw an exception if it fails to meet the constraint. The base class should also take care of the implicit conversion operation to T, and should handle equality by overloading object.Equals(object) and object.GetHashCode(), defining == and != operators for the type ConstrainedNumber<T>
, and implementing IEquatable<T>
and IEquatable<ConstrainedNumber<T>>
. I also recommend defining an copy constructor for the base class, and all derived types. Cloning can then be implemented cleanly in the base class by retrieving the copy constructor via reflection, but this is entirely optional. You can figure out the ConstrainedNumber<T>
implementation yourself, unless I've already posted it on stackoverflow somewhere.
如果使用此技术,请创建一个通用的不可变基类,例如ConstrainedNumber<T>
,它具有接受 T 值和委托的约束的构造函数:delegate bool NumberConstraint<T>(T value)
。构造函数应通过约束委托运行该值,如果不满足约束则抛出异常。基类还应处理到 T 的隐式转换操作,并应通过重载 object.Equals(object) 和 object.GetHashCode()、为 type 定义 == 和 != 运算符ConstrainedNumber<T>
以及实现IEquatable<T>
and来处理相等性IEquatable<ConstrainedNumber<T>>
。我还建议为基类和所有派生类型定义一个复制构造函数。然后可以通过反射检索复制构造函数在基类中干净地实现克隆,但这完全是可选的。你可以弄清楚ConstrainedNumber<T>
自己实现,除非我已经将它发布在 stackoverflow 上的某个地方。
You can provide named static readonly values in your derived ConstrainedNumber, so that you can access them just like an enum.
您可以在派生的 ConstrainedNumber 中提供命名的静态只读值,以便您可以像枚举一样访问它们。
public sealed class ReturnValue: ConstrainedNumber<int>
{
public static readonly NumberConstraint<int> constraint = (int x) => (x >= 0 && x < 3);
public static readonly ReturnValue Success = new ReturnValue(0);
public static readonly ReturnValue FailReason1 = new ReturnValue(1);
public static readonly ReturnValue FailReason2 = new ReturnValue(2);
private ReturnValue( int value ): base( value, constraint ) {}
private ReturnValue( ReturnValue original ): base (original) {} //may be used to support IClonable implementation in base class
public static explicit operator ReturnValue( int value )
{
switch(value) //switching to return an existing instance is more efficient than creating a new one and re-checking the constraint when there is a limited number of allowed values; if the constraint was more generic, such as an even number, then you would instead return a new instance here, and make your constructors public.
{
case 0: return Success;
case 1: return FailReason1;
case 2: return FailReason2;
}
throw new ArgumentException( "Value fails to meet the constraint defined for " + typeof(ReturnValue).FullName + ".", "value" );
}
}
You could use this technique for any constraint. For example, a class called EvenNumber may have a constraint that returns true if the given number is even. In that case, you'd just make your constructors public, and simplify your static conversion operator to just return a new EvenNumber, instead of switching to return one of the limited existing instances.
您可以将此技术用于任何约束。例如,一个名为 EvenNumber 的类可能有一个约束,如果给定的数字是偶数,则返回 true。在这种情况下,您只需公开您的构造函数,并简化您的静态转换运算符以仅返回一个新的 EvenNumber,而不是切换到返回有限的现有实例之一。
It could be used like this:
它可以像这样使用:
EvenNumber x = (EvenNumber)2;
EvenNumber y = (EvenNumber)3; //throws exception "Value fails to meet the constraint defined for {namespace}.EvenNumber." A c# enum would stupidly allow such a cast, creating an invalid EvenNumber, breaking the object-oriented model
int z = x; //implicit conversion, no cast necessary;
回答by Hajoseb
How about using static Members of a Class?
如何使用类的静态成员?
//enum DocInfos { DocName, DocNumber, DocVersion};
public class DocInfos
{
public static int DocName = 0;
public static int DocNumer = 1;
public static int DocVersion = 2;
}
...
...
Doc = new string[DocInfos.DocVersion];
// Treffer
Doc[DocInfos.DocName] = TrimB(HTMLLines[lineCounter + 2])
...
...