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 :(得分: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
以及type参数是否为SomeType
的子类型。在这种情况下,我们得到了一些派生类型的列表,因此我们可以将它转换为SomeType
值的序列(这与使用派生类型的值列表略有不同,但它应该无关紧要用于实际目的)。
答案 1 :(得分:3)
不,遗憾的是不可能做到这样的事情 - CLR没有提供任何有效的方式来进行这种类型的测试。有关一些(相当难看的)解决方案,请参阅How to cast an object to a list of generic type in F#和F# and pattern matching on generics in a non-generic method implementing an interface。
答案 2 :(得分:2)
我后来需要类似的东西来匹配Lazy实例。这是我的解决方案,万一有人发现它有用。
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>"
答案 3 :(得分: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())
答案 4 :(得分:0)
根据F# 2.0 specification,par。 14.5.2(解决子类型约束),它不起作用,因为:“F#泛型类型不支持协方差或逆变。”