为什么即使枚举中没有定义有效值也允许枚举转换

发布于 2024-11-19 08:04:29 字数 648 浏览 10 评论 0原文

在阅读Jon Skeet对此特定问题的回答时我怎样才能使我的类变量只能设置为三个选择之一? 你学到了一些我在 C# 中不知道的新东西,我猜CLR 类型系统。

这是合法的背后的原因是什么:

public enum Tests
{
    Zero = 0,
    One,
    Two
}

var nonExistantTestsValue = (Tests)1000;

这将编译得很好,但我不明白为什么会这样。据我所知,枚举的全部要点是将指定类型的给定变量的值限制为一定数量的选项。

如果 enum 定义所施加的限制如此容易被打破,那么还有什么意义(除了可读性问题)?显然,您可以使用反射来确保它是一个有效值,但为什么不在编译时完成呢?

这样做可能有一个很好的理由,但我看不到它。

When reading Jon Skeet's answer to this particular question How can I make it so my class variables can only be set to one of three choices? y learned something new I was not aware of in C# and I guess the CLR type system.

What is the reasoning behind this being legal:

public enum Tests
{
    Zero = 0,
    One,
    Two
}

var nonExistantTestsValue = (Tests)1000;

This will compile perfectly fine but I fail to see the reason of why it should be so. The whole point of enumerations as far as I can see is to limit to a certain number of options the value of a given variable of the specified type.

If the limitation imposed by the enum definition is so easily broken, what is the point (besides the readability issue)? You can obviously make sure it is a valid value using reflection but why isn't this done at compile time?

There is probably a good reason for this to work the way it does but I fail to see it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

甜`诱少女 2024-11-26 08:04:29

Enumerations are essentially unique types that allow you to assign symbolic names to integral values. They are not used for restricting the allowable values of a variable...

肩上的翅膀 2024-11-26 08:04:29

如果枚举定义所施加的限制如此容易被打破,那还有什么意义

我认为枚举抽象的设计没有考虑到限制或保证有什么意义。我认为它的设计考虑了便利性可维护性

良好的理由:

如果您现在不想看到简单的事实,请跳过第一个项目符号 >

  • 语言规范 [我提到这一点的原因是提醒人们辩论事实的使用有限;像 ... 那么有什么意义 会为我触发这个]
  • 性能(很难/不可能判断何时不需要验证,这会在很大程度上影响特定应用程序的性能

(记住 CLR 函数可以从任何地方调用,而不仅仅是 C#,不仅仅是 < em>你的集会)

If the limitation imposed by the enum definition is so easily broken, what is the point

I think the enum abstraction was not designed with limitation or guarantees in mind. I think it was designed with convenience and maintainability in mind

Good reasons:

Skip the first bullet if you don't want to see simple truths rigth now

  • the language specification [the reason I mention this is to remind people about the limited use of debating facts; a phrase like ... then what's the point triggers this for me]

  • performance (its hard/impossible to tell when a validation would not needed and this would hamper performance in a big way for specific applications

(Remember CLR functions can be called from anywhere, not just C#, not just your assembly)

浅笑轻吟梦一曲 2024-11-26 08:04:29

当枚举不限于这些值时,您可以做什么更令人质疑:

Flags 是这些示例之一:

[Flags]
enum MyFlag
{
     a,
     b,
     c
}

现在您可以执行位操作:

MyFlag flags = MyFlag.a|MyFlag.b;

It is more questioning in what you can do when enums are not limited to there values:

Flags is one of these examples:

[Flags]
enum MyFlag
{
     a,
     b,
     c
}

Now you can do bit operations:

MyFlag flags = MyFlag.a|MyFlag.b;
中二柚 2024-11-26 08:04:29

允许使用任何值,因为您可以使用“Flags”属性来标记枚举。这意味着您可以通过对枚举本身的各个成员进行“或”运算来组成任何值。
基本上,编译器不够智能,无法处理使用枚举的任何可能的方式。

编辑:找到埃里克·利珀特(Eric Lippert)之前的帖子:

为什么将 int 转换为无效的枚举值不会引发异常?

It is allowed any value because you may mark the enum with the "Flags" attribute. That means you may compose any value by OR-ing various members of the enum itself.
Basically the compiler is not smart enough to take care of any possible way where the enum is used.

EDIT: found a previous post by Eric Lippert:

Why does casting int to invalid enum value NOT throw exception?

娜些时光,永不杰束 2024-11-26 08:04:29

我不知道这个设计决定的原因,但我们可以看看它的一些后果。

让我们看一下枚举的 IL 表示:

.class private auto ansi sealed MyEnum
    extends [mscorlib]System.Enum
{
    // Fields
    .field public specialname rtspecialname int32 value__
    .field public static literal valuetype MyEnum Value0 = int32(0)
    .field public static literal valuetype MyEnum Value1 = int32(1)
    .field public static literal valuetype MyEnum Value2 = int32(2)

}

首先我们注意到它是一个值类型,因此 (MyEnum)0 必须有效。其次,我们看到枚举的可能值只是 const,并且运行时级别的枚举与整数文字兼容。

枚举常量通常会变成整数文字。因此,如果您想防止出现无效的枚举,则需要在从枚举转换时引入昂贵的运行时检查,或者引入重要的跨程序集加载时间检查,以确保烘焙到另一个程序集中的枚举文字是有效的。


另一件事是可以创建由 long 支持的枚举。但长整型的一个特性是它们的赋值不能保证是原子的。因此,保证基于 long 的枚举值有效是很困难的。

enum MyLongEnum:long
{
  Value1=0x0101010102020202,
  Value2=0x0303030304040404
}

如果您从多个线程分配给此类枚举,即使您从未分配过无效值,最终也可能会得到无效的混合值。


还有一个简单的解决方法来获得安全的枚举:使用具有私有构造函数的类以及可能值的静态只读字段或属性。这样你就失去了整数转换、文字和不可空性,但获得了类型安全和更好的版本控制。

I don't know about the reasons for this design decision, but we can look at a few of its consequences.

Let's look at the IL representation of an enum:

.class private auto ansi sealed MyEnum
    extends [mscorlib]System.Enum
{
    // Fields
    .field public specialname rtspecialname int32 value__
    .field public static literal valuetype MyEnum Value0 = int32(0)
    .field public static literal valuetype MyEnum Value1 = int32(1)
    .field public static literal valuetype MyEnum Value2 = int32(2)

}

First we note that it is a value type and thus (MyEnum)0 must be valid. Second we see that the possible values of the enums are just consts and that enums at the runtime level are assignment compatible to integer literals.

Enum constants generally become an integer literal. So if you wanted to prevent invalid enums from appearing you'd need to introduce either expensive runtime checks when converting from an enum, or non trivial cross assembly load time checks to make sure enum literals baked into another assembly are valid.


Another thing is that it is possible to create enums backed by a long. But one property of longs is that their assignment is not guaranteed to be atomic. So guaranteeing that the value of a long based enum is valid is hard.

enum MyLongEnum:long
{
  Value1=0x0101010102020202,
  Value2=0x0303030304040404
}

If you assigned to such an enum from multiple threads you can end up with a mixed value that's invalid even if you never assigned an invalid value.


There is also an easy workaround to get safe enums: Use a class with a private constructor and static readonly fields or properties for the possible values. This way you lose integer conversions, literals and non-nullability, but gain type safety and better versioning.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文