2010-09-21 57 views
6
match value with 
| :? list<#SomeType> as l -> l //Is it possible to match any list of a type derived from SomeType? 
| _ -> failwith "doesn't match" 
+0

不,我想這是重要的,但爲什麼你需要匹配某種類型的列表?如果列表是同質的,那麼你可以簡單地按列表處理列表元素,這很好。如果列表是異構的,那麼無論如何您都不能將列表視爲邏輯單元。你想在這裏解決什麼問題? – 2010-09-22 01:08:42

+0

我想我應該使用我的實際代碼。爲了簡單起見,我只是使用列表。問題是如何對類型參數進行靈活的匹配。 – Daniel 2010-09-22 03:27:59

回答

8

正如已經指出的那樣,沒有辦法直接這樣做(模式匹配只能綁定值,但它不能綁定新的類型變量)。除了(更普遍)的解決方法由KVB你可以使用一個事實,即所有集合實現非通用IEnumerable,所以你可以檢查這個類型:值

match box value with 
| :? System.Collections.IEnumerable as l when 
    // assumes that the actual type of 'l' is 'List<T>' or some other type 
    // with single generic type parameter (this is not fully correct, because 
    // it could be other type too, but we can ignore this for now) 
    typedefof<SomeType>.IsAssignableFrom 
     (value.GetType().GetGenericArguments().[0]) -> 
    l |> Seq.cast<SomeType> 
| _ -> failwith "doesn't match" 

的代碼測試是否是非泛型IEnumerable以及類型參數是否爲SomeType的子類型。在這種情況下,我們得到了一些派生類型的列表,所以我們可以將其轉換爲SomeType值的序列(這與使用派生類型的值列表稍有不同,但對於實際目的應該沒有關係) 。

2

我以後需要一些類似的匹配懶惰實例。這是我的解決方案,以防有人發現它有幫助。

let (|Lazy|_|) (value : obj) = 
    if box value <> null then 
     let typ = value.GetType() 
     if typ.IsGenericType && typ.GetGenericTypeDefinition() = typedefof<Lazy<_>> then 
      Some(typ.GetGenericArguments().[0]) 
     else None 
    else None 

用法:

match value with 
| Lazy typ when typeof<SomeType>.IsAssignableFrom(typ) -> (value :?> Lazy<_>).Value 
| _ -> failwith "not an instance of Lazy<#SomeType>" 
0

按照F# 2.0 specification,不相上下。 14.5.2(解決子類型約束),它不起作用,因爲:「F#泛型類型不支持協變或逆變。」

1

不乾淨的,但有效:

let matchType<'T>() = 
    try 
     let o = Activator.CreateInstance<'T>() 
     match box o with 
     | :? Type1 -> printfn "Type1" 
     | :? Type2 -> printfn "Type2" 
     | _ -> failwith "unknown type" 
    with 
    | ex -> failwith "%s" (ex.ToString())