2016-07-27 10 views
7

stworzyłem rur stanie ofType<'T> funkcję sekwencji opartej na Enumerable.OfType<'T>():błąd Rodzaj związane z rodzajowych w zależności od lokalizacji funkcji

let ofType<'T> (sequence : _ seq) = sequence.OfType<'T>() 

Używając tego w tym samym .fsx pliku działa dobrze; to nadal robi kiedy mogę umieścić go w module:

module Seq = 
    let ofType<'T> (sequence : _ seq) = sequence.OfType<'T>() 

przestaje działać kiedy przenieść go do innego pliku skryptu i (być w stanie uzyskać do niego dostęp z zewnątrz) zawinąć go w innym module najwyższego poziomu:

module Prelude = 
    open System.Linq 

    module Seq = 
     let ofType<'T> (sequence : _ seq) = sequence.OfType<'T>() 

odwołać to z mojego oryginalnego pliku skryptu, otwórz moduł Prelude i wywołać funkcję tak:

let getXmlIncludes (xtype : Type) = 
    xtype.GetCustomAttributes() |> Seq.ofType<XmlIncludeAttribute> 

który powoduje Seq.ofType<XmlIncludeAttribute> być marke d jako błąd z komunikatem

error FS0001: Type mismatch. Expecting a 
    Collections.Generic.IEnumerable<Attribute> -> 'a  
> but given a 
    Collections.Generic.IEnumerable<Attribute> -> Collections.Generic.IEnumerable<XmlIncludeAttribute>  
The type 'obj' does not match the type 'Attribute' 

Błąd pozostaje taka sama kiedy przenieść ofType<'T> bezpośrednio do modułu Prelude.

Dlaczego tak się dzieje i jak mogę to uniemożliwić?

(próbowałem zmianę rodzaju _ seq parametru do 'TSeq seqsequence, co skutkuje niezwykle popularnej

warning FS0064: This construct causes code to be less generic than indicated by the type annotations. The type variable 'TSeq has been constrained to be type 'obj'. 

ale wie nic o błędzie nie zmieni).

+0

I nie wydają się odtworzyć swój błąd. Może mógłbyś zapewnić repozytorium demonstrujące błąd. – Ringil

+1

Czy istniejący 'Seq.cast' już nie jest w nazwie" Enumerable.OfType "? – Sehnsucht

+1

@Sehnsucht 'TypTylko ' jest takie samo jak '.Where (x => x to typeof (T))', np. filtr według typu. Śledź mój pierwszy link z odpowiedzi, a zobaczysz zarówno implementacje "OfType" i "Cast" na tym samym ekranie. –

Odpowiedz

7

Enumerable.OfType<'T>() jest not generic w odniesieniu do parametru wejściowego. Po zmianie _ seq na nietypowy IEnumerable błąd zniknie.

open System 
open System.Collections 
open System.Reflection 
open System.Xml.Serialization 

module Prelude = 
    open System.Linq 
    module Seq = 
     let inline ofType<'T> (sequence : IEnumerable) = sequence.OfType<'T>() 

open Prelude 
let getXmlIncludes (xtype : Type) = 
    xtype.GetCustomAttributes() |> Seq.ofType<XmlIncludeAttribute> 

W oryginalnym kodzie (sequence : _ seq) jest ograniczony do seq<Attribute>, ale F # does typ not wsparcie kowariancji i nie może pracować z seq<XmlIncludeAttribute> jakby to było seq<Attribute>, choć XmlIncludeAttribute dziedziczy Attribute. Ale nawet jeśli F # wspierał kowariancję, Twój przykład zadziałałby tylko dla tego konkretnego przypadku plus tylko dla typów dziedziczących po Attribute.

Można wyraźnie zauważyć błąd, jeśli spróbujesz użyć rozszerzenia Seq z innego typu:

let getIntsAsUints (list : List<int>) = 
    list |> Seq.ofType<uint32> 

Script.fsx(21,13): error FS0001: The type 'List<int>' is not compatible with the type 'seq<Attribute>' 
+0

Dzięki; '.OfType <'T>()' praca nad nietypowym 'IEnumerable' była tym, co przeoczyłem. – TeaDrivenDev

Powiązane problemy