Dot-Net

F# int.MaxValue 是“不是一個有效的常量表達式”,但 System.Int32.MaxValue 是?

  • July 9, 2016

TL;DR: F# 編譯器int在此上下文中解釋為intoperator由 Eugene Fotin 確定並由Gene Belitski 擴展。最好的解決方法是使用System.Int32.MaxValue如下所述的唯一類型別名。


考慮以下記錄類型:

type User = {
   Username : string
}

我想要Username至少三個字元長,所以我使用StringLength屬性。沒有最大長度,所以我將其設置為int.MaxValue

type User = {
   [<StringLength(int.MaxValue, MinimumLength=3)>]
   Username : string
}

這給了我以下錯誤:

這不是有效的常量表達式或自定義屬性值。

如果我改用,一切都很美好System.Int32

type User = {
   [<StringLength(System.Int32.MaxValue, MinimumLength=3)>]
   Username : string
}

如果我別名,它也會編譯int

type User = {
   [<StringLength(num.MaxValue, MinimumLength=3)>]
   Username : string
}
and num = int

或完全限定類型:

type User = {
   [<StringLength(Microsoft.FSharp.Core.int.MaxValue, MinimumLength=3)>]
   Username : string
}

我簽入了 F# 原始碼,並int完全按照您的預期定義

type int32 = System.Int32
// Then, a few lines later…
type int = int32

這是怎麼回事?我假設 F# 原始類型在大多數情況下可以與其他類型互換,但看起來我的心智模型中缺少某些東西。

這就是 F# 類型推斷在不同上下文中工作的方式,其中不同的句法實體巧合地具有相同的名稱,在這種情況下int可能是以下任何一種:

  • int:'T->int全名的作用Microsoft.FSharp.Core.Operators.int
  • type int = int32全名Microsoft.FSharp.Core.int
  • type int<'Measure> = int全名Microsoft.FSharp.Core.int<_>

展示此工作的一種方法是以下場景:如果我們只是輸入

int;;

在 FSI 我們會得到類似的東西

val it : (int -> int) = <fun:it@3>

換句話說,它是一個不能有MaxValue與之關聯的屬性的函式:

> int.MaxValue;;

int.MaxValue;;
----^^^^^^^^

... error FS0039: The field, constructor or member 'MaxValue' is not defined

這同樣適用於int32,當在表達式上下文中使用時,FSI 將其推斷為另一個帶有簽名的函式(int -> int32)

現在說到

type num = int

在這種情況下int,推斷為 的類型名稱縮寫System.Int32num類型縮寫也是如此,但現在名稱歧義沒有位置,因此num.MaxValue推斷出的正是我們所期望的,在 FSI 中給出

> num.MaxValue;;
val it : int = 2147483647

最後,當您使用Microsoft.FSharp.Core.int顯式引用類型實體時,沒有歧義的地方,因此它按預期工作。

回到帶有屬性參數的案例 - 在這種情況下int,類型推斷將其視為表達式的一部分以傳遞參數值,即作為函式,除非您明確或間接設置另一種解釋。

引用自:https://stackoverflow.com/questions/20271205