确定任何类型的列表、序列、数组或 IEnumerable 是否为空
Determine if any kind of list, sequence, array, or IEnumerable is empty
我正在编写一个 Xamarin.Forms 应用程序,使用 XAML 作为我的观点,我正在尝试编写一个 IValueConverter
如果输入,它的工作应该返回 false
"empty" 对于那些语义有意义的类型 (strings/lists/sequences/arrays/IEnumerables)。我从以下内容开始,对于空字符串 returns false,但我不知道如何将其扩展到列表、序列、数组和 IEnumerables:
type FalseIfEmptyConverter() =
interface IValueConverter with
member __.Convert(value:obj, _, _, _) =
match value with
| :? string as s -> (s <> "" && not (isNull s)) |> box
// TODO: extend to enumerables
| x -> invalidOp <| "unsupported type " + x.GetType().FullName
member __.ConvertBack(_, _, _, _) =
raise <| System.NotImplementedException()
我尝试过但不起作用的方法:
:? list<_>
不匹配(盒装)列表(至少不是整数)并产生警告 This construct causes code to be less generic than indicated by its type annotations. The type variable implied by the use of a '#', '_' or other type annotation at or near [...] has been constrained to be type 'obj'
:? list<obj>
不会产生警告,但也不匹配装箱的整数列表
- 与
:? seq<_>
和:? seq<obj>
相同
- 它与
:? System.Collections.Generic.IEnumerable<obj>
和 IEnumerable<_>
相同(如果我将它放在上面给出的类似 seq
匹配下方,它会警告该规则永远不会匹配,这有道理,因为 AFAIK seq
对应于 IEnumerable
)
利用Foggy Finder的思路来使用非泛型IEnumerable
:
let isEmpty (x:obj) =
match x with
| null -> true
| :? System.Collections.IEnumerable as xs -> xs |> Seq.cast |> Seq.isEmpty
| _ -> invalidOp <| "unsupported type " + x.GetType().FullName
isEmpty "" // true
isEmpty [] // true
isEmpty (set []) // true
isEmpty [||] // true
isEmpty null // true
isEmpty "a" // false
isEmpty [|1|] // false
isEmpty 1 // exception
您要测试的所有类型都是 Seq<'a>
的子类型,这与 IEnumerable<'a>
完全相同(包括 string
,它是 seq<char>
).但这也是称为 IEnumerable
的非泛型类型的子类型(注意缺少类型参数)。这类似于 IEnumerable<obj>
,其中每个项目都已装箱。这就是为什么我们可以将所有这些转换为 IEnumerable
,然后使用 Seq.cast
将其转换为 IEnumerable<obj>
,这样我们就可以使用 Seq.empty
,它只适用于泛型.
我正在编写一个 Xamarin.Forms 应用程序,使用 XAML 作为我的观点,我正在尝试编写一个 IValueConverter
如果输入,它的工作应该返回 false
"empty" 对于那些语义有意义的类型 (strings/lists/sequences/arrays/IEnumerables)。我从以下内容开始,对于空字符串 returns false,但我不知道如何将其扩展到列表、序列、数组和 IEnumerables:
type FalseIfEmptyConverter() =
interface IValueConverter with
member __.Convert(value:obj, _, _, _) =
match value with
| :? string as s -> (s <> "" && not (isNull s)) |> box
// TODO: extend to enumerables
| x -> invalidOp <| "unsupported type " + x.GetType().FullName
member __.ConvertBack(_, _, _, _) =
raise <| System.NotImplementedException()
我尝试过但不起作用的方法:
:? list<_>
不匹配(盒装)列表(至少不是整数)并产生警告This construct causes code to be less generic than indicated by its type annotations. The type variable implied by the use of a '#', '_' or other type annotation at or near [...] has been constrained to be type 'obj'
:? list<obj>
不会产生警告,但也不匹配装箱的整数列表- 与
:? seq<_>
和:? seq<obj>
相同 - 它与
:? System.Collections.Generic.IEnumerable<obj>
和IEnumerable<_>
相同(如果我将它放在上面给出的类似seq
匹配下方,它会警告该规则永远不会匹配,这有道理,因为 AFAIKseq
对应于IEnumerable
)
利用Foggy Finder的思路来使用非泛型IEnumerable
:
let isEmpty (x:obj) =
match x with
| null -> true
| :? System.Collections.IEnumerable as xs -> xs |> Seq.cast |> Seq.isEmpty
| _ -> invalidOp <| "unsupported type " + x.GetType().FullName
isEmpty "" // true
isEmpty [] // true
isEmpty (set []) // true
isEmpty [||] // true
isEmpty null // true
isEmpty "a" // false
isEmpty [|1|] // false
isEmpty 1 // exception
您要测试的所有类型都是 Seq<'a>
的子类型,这与 IEnumerable<'a>
完全相同(包括 string
,它是 seq<char>
).但这也是称为 IEnumerable
的非泛型类型的子类型(注意缺少类型参数)。这类似于 IEnumerable<obj>
,其中每个项目都已装箱。这就是为什么我们可以将所有这些转换为 IEnumerable
,然后使用 Seq.cast
将其转换为 IEnumerable<obj>
,这样我们就可以使用 Seq.empty
,它只适用于泛型.