确定任何类型的列表,序列,数组或IEnumerable是否为空

时间:2017-11-14 08:05:59

标签: f# ivalueconverter

我正在使用XAML为我的观点编写一个Xamarin.Forms应用程序,我正在尝试编写一个IValueConverter,如果输入为"空&#34,其作业应返回false ;对于那些语义有意义的类型(strings / lists / sequences / arrays / IEnumerables)。我已经开始使用以下内容,它为空字符串返回false,但我无法弄清楚如何将其扩展为列表,序列,数组和IEnumebles:

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

1 个答案:

答案 0 :(得分:6)

使用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,这只适用于泛型类型