2

F#列挙型宣言について考えてみます。

type MyEnum =
  | A = 1
  | B = 2

これで、MyEnumタイプの値を作成できます。

let enumValue1 = MyEnum.A

値enumValue1は、タイプMyEnumを持つと推測されます。

ただし、列挙型のインスタンスを作成することもできます。

let enumValue2 = new MyEnum()

値enumValue2もMyEnumタイプです。

列挙型は整数型のラッパーであり、列挙型はスタックに格納されていることを読みました。

ただし、上記のコードスニペットでは、列挙型をインスタンス化します。このインスタンスはヒープに保存されますか?

本質的に、列挙型がスタックに格納されているのかヒープに格納されているのか(または状況によっては両方に格納されているのか)混乱していますか?

トリックは機能しません:

typeof<MyEnum>.BaseType = typeof<System.ValueType> 

...列挙型はSystem.Enum型であるため

4

3 に答える 3

1

まず、あなたの混乱newはC++から来ていると思います。MyEnum e = MyEnum();そこでは、またはのようなものを書くことができますMyEnum* e = new MyEnum();。それぞれが異なることを意味します。C#にはそのような区別はなく、を使用して値を作成するかどうかは関係ありませnewん。

列挙型がスタックに格納されていることを読みました[…]。

それはひどく単純化しすぎているので、このように言うと間違っていると思います。Enumsはスタックに格納できますが、ヒープまたはレジスタに格納することもできます。そして、ほとんどの場合、それらが正確にどこに保存されているかは問題ではありません。

ただし、上記のコードスニペットでは、列挙型をインスタンス化します。このインスタンスはヒープに保存されますか?

上で言ったように、あなたが使用したかどうかは関係ありません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

let a = (fun() -> MyEnum.A)()

let getA() = a  
    
printfn "%A" (getA())

aより複雑な初期化を行うということは、以前の最適化が使用されずa、静的フィールドに格納されることを意味します(これらは通常、ヒープの特別なセクションに格納されます)。


したがって、ご覧のとおり、値が正確に格納される場所は非常に複雑で、コンパイラ固有の場合があります。そして、マイクロ最適化を実行しているのでない限り、それを気にする必要はありません。また、それは確かにとは何の関係もありませんnew

トリックは機能しません:

typeof<MyEnum>.BaseType = typeof<System.ValueType> 

…列挙型はSystem.Enum型であるため

しかし、Enumそれ自体はから派生してValueTypeいるので、これは次を返しますtrue

typeof<MyEnum>.BaseType.BaseType = typeof<System.ValueType>

System.Enumとそれ自体が参照型であるという事実System.ValueTypeは、状況をさらに混乱させますが。

于 2013-01-27T21:59:18.653 に答える
0

.NETのnewキーワードは、C ++のnewキーワード(ヒープからメモリを割り当てる)とは異なります。.NETではnew、オブジェクトの新しいインスタンスを作成し、そのコンストラクターを呼び出します(コンストラクターがある場合)。その新しいオブジェクトがヒープ上にあるかスタック上にあるかは、通常、使用したかどうかではなく、値型か参照型かによって異なりますnew

intsおよびその他のプリミティブにも0引数のコンストラクターがあることに注意してください。

new Int16()

またはプリミティブ型で使用newするEnumと、デフォルト値(通常は0)でその型のインスタンスが作成されます。

于 2013-01-27T15:56:26.163 に答える
0

new MyEnum().NETでは、すべての値型にパラメーターのないパブリックコンストラクターが必要であるため、これらをインスタンス化できます。列挙型の場合、これは列挙型に0をキャストするようなものです。

> LanguagePrimitives.EnumOfValue<_,MyEnum> 0;;
val it : MyEnum = 0

列挙型が実際に値型であることを確認することもできます。

> typeof<MyEnum>.IsSubclassOf typeof<System.ValueType>;;
val it : bool = true
于 2013-01-27T15:56:32.983 に答える