Unfortunately, there is no way to make it beautiful. If you have control over the Template<'T> , the best option is to create a non-generic interface (for example, ITemplate ) and implement it in the Template<'T> . Then you can just check the interface:
| :? ITemplate as t -> ...
If not, then your only option is to use reflection magic. You can implement an active template that matches when the type is some value of Template<'T> , and returns a list of types ( System.Type objects) that were used as general arguments. In your pseudo-code, you wanted to get this as a parameter of type type 'a - it is impossible to get it as a parameter of type compilation time, but you can get it as information like runtime type:
let (|GenericTemplate|_|) l = let lty = typeof<list<int>>.GetGenericTypeDefinition() let aty = l.GetType() if aty.IsGenericType && aty.GetGenericTypeDefinition() = lty then Some(aty.GetGenericArguments()) else None
Now you can write the following pattern matching code:
match result with | GenericTemplate tys ->
The final issue is how you can use this runtime type information to run some common code. The best option I can come up with is to call a common method (or function) using reflection - then you can specify information such as runtime as a general parameter, and therefore the code can be shared. The easiest option is to call a static member of the type:
type TemplateHandler = static member Handle<'T>(arg:Template<'T>) =
The basic idea is that you move the pattern matching body (which cannot have type type parameters) to the method (which can have common type parameters) and dynamically run the method using reflection.
You can change the code to use the let function instead of the static member , but finding a function that uses reflection is a bit more complicated.
Tomas petricek
source share