Сравнение шаблонов с универсальным типом с использованием параметра типа «Flexible» - PullRequest
6 голосов
/ 22 сентября 2010
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"

Ответы [ 5 ]

8 голосов
/ 22 сентября 2010

Как уже указывалось, прямого способа сделать это невозможно (сопоставление с образцом может связывать только значения, но не может связывать переменные нового типа).В дополнение к (более общему) обходу 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 (это немного отличается от работы со списком значений производных типов, но это не должно иметь значения для практического применения).цели).

3 голосов
/ 22 сентября 2010

Нет, к сожалению, сделать что-то подобное невозможно - CLR не предоставляет эффективного способа проверки типа. См. Как привести объект к списку универсального типа в F # и F # и сопоставлению с шаблоном в универсальных методах, реализующих интерфейс для нескольких (довольно уродливых) решений .

2 голосов
/ 23 сентября 2010

Мне позже понадобилось нечто подобное для сопоставления экземпляров 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>"
1 голос
/ 10 сентября 2013

Не самый чистый, но эффективный:

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())
0 голосов
/ 19 июля 2011

Согласно спецификации F # 2.0 , пар. 14.5.2 (Решение ограничений подтипов), он не будет работать, потому что: «Универсальные типы F # не поддерживают ковариацию или контравариантность».

...