考虑F#Enum声明:
type MyEnum =
| A = 1
| B = 2
我现在可以创建MyEnum类型的值:
let enumValue1 = MyEnum.A
推断值enumValue1的类型为MyEnum。
但是我也可以创建一个Enum类型的实例:
let enumValue2 = new MyEnum()
值enumValue2也是MyEnum类型。
我读到Enum类型是整数类型的包装,而Enum存储在堆栈中。
但是在上面的代码片段中,我实例化了我的Enum类型。这个实例存储在堆上?
本质上我很困惑Enums是存储在堆栈还是堆上(或者两者都可以根据情况而存在)?
诀窍不起作用:
typeof<MyEnum>.BaseType = typeof<System.ValueType>
...因为Enums的类型为System.Enum
答案 0 :(得分:1)
首先,我认为您对new
的困惑来自C ++。在那里,您可以编写MyEnum e = MyEnum();
或MyEnum* e = new MyEnum();
之类的内容,其中每个内容都有所不同。在C#中没有这样的区别,是否使用new
创建值无关紧要。
我读到[...]枚举存储在堆栈中。
这是粗略的过度简化,我会说这是错的,当这样说时。 Enum
可以存储在堆栈中,是的,但它们也可以存储在堆上或寄存器中。在大多数情况下,它们存储的确切位置并不重要。
但是在上面的代码片段中,我实例化了我的Enum类型。这个实例存储在堆上?
就像我上面说的那样,使用new
并不重要。存储值的确切位置取决于具体情况。
如果变量实际上是一个简单的本地:
let a = MyEnum.A
printfn "%A" a
然后它将存储在堆栈或寄存器中。
但您也可以使用相同的语法来定义类型的字段:
type Test() =
let a = MyEnum.A
member this.A
with get() = a
printfn "%A" (Test().A)
在这种情况下,Test
是一个.Net类,它是一个引用类型,因此a
将存储在为某些Test
对象分配的内存中的堆上。
但也有不太明显的案例。例如:
let a = MyEnum.A
let getA() = a
printfn "%A" (getA())
在这种情况下,本地a
将不会存储在任何地方,因为getA()
的代码将被优化以直接返回MyEnum.A
。< / p>
let a = (fun() -> MyEnum.A)()
let getA() = a
printfn "%A" (getA())
使a
的初始化更复杂意味着不会使用先前的优化,并且a
现在存储在静态字段中(那些通常存储在堆的特殊部分中)。
因此,正如您所看到的,存储值的确切位置可能非常复杂并且特定于编译器。除非你进行微观优化,否则你不应该关心它。此外,它肯定与new
没有任何关系。
诀窍不起作用:
typeof<MyEnum>.BaseType = typeof<System.ValueType>
...因为Enums的类型为System.Enum
但Enum
本身来自ValueType
,因此返回true
:
typeof<MyEnum>.BaseType.BaseType = typeof<System.ValueType>
虽然System.Enum
和System.ValueType
本身就是引用类型,但这种情况更令人困惑。
答案 1 :(得分:0)
.NET中的new
关键字与C ++的new
关键字(从堆中分配内存)不同。在.NET中,new
只是创建一个对象的新实例并调用其构造函数(如果有的话)。新对象是在堆上还是堆栈上,通常取决于它是值类型还是引用类型,而不是您是否使用new
。
可以注意到int
和其他原语也有0参数构造函数:
new Int16()
在new
或基本类型上使用Enum
只会创建该类型的实例及其默认值(通常为0)。
答案 2 :(得分:0)
您可以将它们实例化为new MyEnum()
,因为在.NET中,所有值类型都需要具有无参数的公共构造函数。对于枚举,这就像将0转换为枚举类型:
> LanguagePrimitives.EnumOfValue<_,MyEnum> 0;;
val it : MyEnum = 0
您还可以检查枚举是否实际上是值类型:
> typeof<MyEnum>.IsSubclassOf typeof<System.ValueType>;;
val it : bool = true