【问题标题】:Determine if any kind of list, sequence, array, or IEnumerable is empty确定任何类型的列表、序列、数组或 IEnumerable 是否为空
【发布时间】:2017-11-14 08:05:59
【问题描述】:

我正在为我的视图编写一个使用 XAML 的 Xamarin.Forms 应用程序,并且我正在尝试编写一个 IValueConverter,如果对于这些语义有意义的类型输入为“空”,则其工作应该返回 false(字符串/列表/序列/数组/IEnumerables)。我从以下开始,它为空字符串返回 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&lt;_&gt; 不匹配(盒装)列表(至少不是整数)并产生警告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&lt;obj&gt; 不会产生警告,但也不匹配装箱的整数列表
  • :? seq&lt;_&gt;:? seq&lt;obj&gt; 相同
  • 这与:? System.Collections.Generic.IEnumerable&lt;obj&gt;IEnumerable&lt;_&gt; 相同(如果我将它放在与上面给出的类似seq 匹配的下方,它会警告该规则永远不会匹配,这是有道理的,因为AFAIK seq 对应到IEnumerable)

【问题讨论】:

  • match value with | :? System.Collections.IEnumerable as s -&gt; s.GetEnumerator().MoveNext() |&gt; not | x -&gt; invalidOp &lt;| "unsupported type " + x.GetType().FullName

标签: f# ivalueconverter


【解决方案1】:

使用 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&lt;'a&gt; 的子类型,它与IEnumerable&lt;'a&gt; 完全相同(包括string,它是seq&lt;char&gt;)。但这也是称为IEnumerable 的非泛型类型的子类型(注意缺少类型参数)。这类似于IEnumerable&lt;obj&gt;,其中每个项目都已装箱。这就是为什么我们可以将所有这些转换为IEnumerable,然后使用Seq.cast 将其转换为IEnumerable&lt;obj&gt;,这样我们就可以使用仅适用于泛型类型的Seq.empty

【讨论】:

  • 效果很好,谢谢!但我真的不明白为什么必须使用IEnumerable 而不是IEnumerable&lt;obj&gt;。你能详细说明一下吗?
  • 在进行类型测试时,stringseq&lt;char&gt;charobj,但 string 不是 seq&lt;obj&gt;。对祖先类型的检查不会扩展到类型参数,即使理论上可以。我不知道为什么 F# 会这样,或者它是否真的是因为 .NET,或者这里是否存在根本性的困难而不是缺少该功能。
  • 谢谢,这清除了它,或多或少是我所怀疑的。
猜你喜欢
  • 2022-06-22
  • 2023-04-08
  • 2010-12-23
  • 1970-01-01
  • 1970-01-01
  • 2018-07-05
  • 2017-09-05
  • 2011-09-07
  • 1970-01-01
相关资源
最近更新 更多