2015-11-07 85 views
1

我目前正在提取有關從這裏型方法的信息是我當前的代碼的相關部分(其中正常工作):爲什麼這個「對於類型測試模式」失敗?

let ctorFlags = BindingFlags.NonPublic ||| BindingFlags.Public ||| BindingFlags.Instance ||| BindingFlags.Static 
let methodFlags = BindingFlags.DeclaredOnly ||| ctorFlags 

[ 
    for t in Assembly.GetExecutingAssembly().GetTypes() do 
     for c in t.GetConstructors ctorFlags -> c :> MethodBase 
     for m in t.GetMethods methodFlags -> m :> MethodBase 
] 
|> printfn "%A" 

然後我想使使用的事實syntaxfor pattern in expr一個小的變化。並且,如果給定的輸入匹配到type test pattern匹配(或派生類型的)給定類型;所以我寫了這個:

// same flags as before 
[ 
    for t in Assembly.GetExecutingAssembly().GetTypes() do 
     for :? MethodBase as m in t.GetConstructors ctorFlags -> m 
     for :? MethodBase as m in t.GetMethods methodFlags -> m 
] 
|> printfn "%A" 

這給了我一個錯誤的GetConstructors線(由我翻譯成英文)

不兼容的類型約束。類型MethodBase與類型ConstructorInfo不兼容。

經過仔細檢查ConstructorInfo源自MethodBase(並且與MethodInfo相同)。

注意:如果使用柔性類型(#MethodBase)代替;該模式的工作原理,但對構造m的類型爲RuntimeConstructorInfo和方法m散列類型RuntimeMethodInfo(什麼是使用靈活型預期的行爲)。我明顯地測試了它們,因爲有兩種不同類型的列表是不允許的。

所以問題是:爲什麼我錯過了/誤解?

+0

如果你使用:中>代替>,這是否解決您的問題? – Foole

+0

@Fole我不使用?>(甚至不知道它存在),以防萬一你的意思是替換:?與:>不能在一個模式中完成,所以只有我可以使用的地方:>將在for的「body」中,這正是我在最初的代碼中完成的。如果你不是那個意思,那我就不明白了。 – Sehnsucht

回答

3

當您嘗試使用:?模式將其轉換爲子類型的超類型(upcast)時,編譯器會報告錯誤,該類型是永遠不會失敗的類型。值得注意的是,當您使用:?模式爲上溯造型其他任何地方,你得到完全相同的錯誤:

match System.Random() with 
| :? obj as o -> o 

我認爲:?模式主要被用於安全的向下轉換(當模式匹配能情況失敗)。例如:

match box 1 with 
| :? string as s -> "string" 
| :? int as n -> "int" 

編譯器檢查你鑄造(這裏stringint)類型是在參數(這裏object)所使用的類型的有效子類型。

轉換stringobject(或ConstructorInfoMethodBase)也將是有效的,但出於不同的原因 - 和編譯器顯然不僅會較爲常見的一種檢查。

您嘗試使用:?絕對會讓很多的意義,我 - 我認爲在編譯器檢查可以放寬,允許這一點。你可以post this as a suggestion to the F# user voice

+0

所以基本上這是文檔中的錯誤,不是嗎?它清楚地表明,派生類型輸入在匹配的地方看起來是相反的:派生類型只允許用於不是輸入部分的情況。 – Sehnsucht

+0

我不同意最新的段落。 '爲:? MethodBase as m in t.GetConstructors ctorFlags - > m' should be'for m in t.GetConstructors ctorFlags - > m:> MethodBase';這些是不同的用例:前者可能不匹配列表中的所有元素,後者是由於F#沒有隱式的upcasts。國際海事組織的潛在過濾語義應該與上傳清楚地分開。 – CaringDev