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

No es que supongo que importa, pero ¿por qué necesita para que coincida con una lista de algún tipo? Si la lista es homogénea, entonces simplemente puede procesar la lista elemento por elemento y eso está bien. Si la lista es heterogénea, entonces no puede considerar la lista como una unidad lógica de todos modos. ¿Cuál es el problema que estás tratando de resolver aquí? –

+0

Supongo que debería haber usado mi código real. Solo estoy usando la lista por simplicidad. La pregunta es cómo hacer una coincidencia flexible en los parámetros de tipo. – Daniel

Respuesta

8

Como ya se señaló, no hay forma de hacerlo directamente (la coincidencia de patrones solo puede vincular valores, pero no puede vincular nuevas variables de tipo). Además de la solución (más general) por kvb puede utilizar el hecho de que todas las colecciones de implementar no genérico IEnumerable, para que pueda comprobar de este 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" 

El código prueba si el valor es una no genérico IEnumerable y si el parámetro de tipo es subtipo de SomeType. En ese caso, tenemos una lista de algún tipo derivado, por lo que podemos convertirlo a una secuencia de valores SomeType (esto es ligeramente diferente de trabajar con la lista de valores de los tipos derivados, pero no debería importar para fines prácticos) .

2

Más tarde necesité algo similar para hacer coincidir las instancias de Lazy. Aquí está mi solución, en caso de que alguien lo encuentre útil.

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 

Uso:

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

De acuerdo con la F# 2.0 specification, par. 14.5.2 (Resolviendo Subtipos de Restricciones), no funcionará, porque: "Los tipos genéricos F # no admiten la covarianza o la contravarianza".

1
No

el más limpio, pero eficaz:

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