2010-09-21 9 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

Non che io immagino è importante, ma perché avete bisogno per abbinare con un elenco di qualche tipo? Se la lista è omogenea, puoi semplicemente elaborare la lista element by element e va bene. Se la lista è eterogenea, non si può comunque considerare l'elenco come un'unità logica. Qual è il problema che stai cercando di risolvere qui? –

+0

Suppongo che avrei dovuto usare il mio codice attuale. Sto solo usando la lista per semplicità. La domanda è come fare una corrispondenza flessibile sui parametri del tipo. – Daniel

risposta

8

Come già sottolineato, non esiste un modo per farlo direttamente (la corrispondenza del modello può solo associare valori, ma non può associare nuove variabili di tipo). Oltre al (più generale) soluzione per KVB è possibile utilizzare il fatto che tutte le collezioni implementano non generico IEnumerable, in modo da poter verificare la presenza di questo tipo:

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" 

Il codice verifica se il valore è un non-generic IEnumerable e se il parametro type è sottotipo di SomeType. In questo caso, abbiamo ottenuto un elenco di alcuni tipi derivati, quindi possiamo lanciarlo su una sequenza di valori SomeType (questo è leggermente diverso rispetto a lavorare con l'elenco di valori dei tipi derivati, ma non dovrebbe essere rilevante per scopi pratici) .

2

Successivamente ho avuto bisogno di qualcosa di simile per l'abbinamento di istanze Lazy. Ecco la mia soluzione, nel caso qualcuno la trovi utile.

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 

Usage:

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

Secondo il F# 2.0 specification, par. 14.5.2 (Risoluzione dei vincoli di sottotipo), non funzionerà, perché: "I tipi di F # non supportano la covarianza o la contravarianza".

1

non il più pulito, ma efficace:

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