2010-09-21 74 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())