2017-11-14 104 views
5

Görünümlerim için XAML kullanarak bir Xamarin.Forms uygulaması yazıyorum ve girdisi false olan işin döndürülmesi gereken bir IValueConverter yazmaya çalışıyorum Bu semantiklerin anlamlı olduğu türler için "boş" (dizeler/listeler/diziler/diziler/IEnumerables). Ben boş dizeleri için false döndüren aşağıdaki malzemeleri başladı ancak ben listeleri, diziler, diziler ve IEnumerables bu genişletmek için nasıl bilemiyorum:Herhangi bir liste, dizi, dizi veya IEnumerable boş olup olmadığını belirleme

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() 

şeyler denedim o don' t work:

  • :? list<_> does not match bir (boxed) list (at least not of ints) ve produces bir warning 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> does not produce the warning, but also does n't match bir boxed list of inrol
  • It 'Nin aynı :? seq<_> ve :? seq<obj> Bu :? System.Collections.Generic.IEnumerable<obj> ve IEnumerable<_> (aynı şey
  • ile ve yukarıda verildiği gibi ben de benzer seq maçın altına yerleştirin, eğer kural eşleşti AFAIK seq tekabül beri mantıklı hangi asla konusunda uyarıyor kullanmak Sisli Finder'ın fikrini kullanarak IEnumerable)
+2

' ile eşleşme değeri | :? System.Collections.IEnumerable s -> s.GetEnumerator(). MoveNext() |> değil | x -> invalidOp <| "Desteklenmeyen tip" + x.GetType(). FullName' –

cevap

6

-IEnumerable olmayan jenerik:

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 

test etmek istediğiniz tiplerinin hepsi

alt türleridir, tam olarak IEnumerable<'a> ( seq<char> olan string dahil) ile aynıdır. Fakat bu aynı zamanda, IEnumerable olarak adlandırılan jenerik olmayan bir türün alt tipidir (tip parametresinin eksikliğine dikkat edin). Bu, her öğenin kutulandığı IEnumerable<obj>'a benzer. Bu nedenle, tüm bunları IEnumerable'a atabiliriz, daha sonra IEnumerable<obj>'a dönüştürmek için Seq.cast kullanın, böylece yalnızca genel türünde çalışan Seq.empty'u kullanabiliriz.

+0

Harika çalışıyor, teşekkürler! Ama gerçekten neden IEnumerable 'yerine IEnumerable kullanması gerektiğini anlamıyorum. Biraz detaylandırır mısın? – cmeeren

+2

Bir tür sınaması yapılırken, bir 'dize'' bir ' dır ve 'char' bir' obj''dir, ancak 'dize' bir ' seq değil. Ataların türleri için kontrol, teoride olabilse de, tip parametrelerine kadar uzanmaz. F # neden bu şekilde davrandığını veya aslında .NET yüzünden mi, yoksa burada temel bir güçlük varsa, yalnızca bir özellik eksikliğiyle. – TheQuickBrownFox

+0

Teşekkürler, bu onu temizler ve şüphelendiğim şeydir. – cmeeren