F# Generics and Casting
after reading all the questions suggested as related, I couldn't find an answer to my question. Writing to you in the hope that you will answer soon and will judge leniently my lack of knowledge in this area.
I have a type to embody a function definition:
type FunctionDefinition<'a>(exec:int->(Data.Reader->'a)) =
member x.Exec = exec
member x.ReturnType = typeof<'a>
As you can see here, exec
is supposed to be a function that takes one int
argument and returns another function that takes one Data.Reader
argument and returns a value of type 'a
(such an exhausting phrase!). The definition of Data.Reader
is irrelevant here.
Also, I have a dictionary to keep string开发者_如何学C->FunctionDefinition
pairs as follows:
let FUNCTIONS = new Generic.Dictionary<string, FunctionDefinition<obj>>()
FunctionDefinition
instances in FUNCTIONS
are going to hold functions of several types and this is why it is FunctionDefinition<obj>
(I believe this the root of the evil, but I cannot avoid this, so I'm here).
Then I have some functions to be wrapped in FunctionDefinition
and put into FUNCTIONS
:
/// Function definitions
let unchanged (id:int) =
let mutable last = null
fun (reader:Data.Reader) ->
if last = null then
false
else
let cur = reader.GetValue(id)
let ret = last.Equals(cur)
last <- cur
ret
let changed (id:int) =
let un = unchanged id
fun(reader:Data.Reader) ->
not (un reader)
let dummyfortesting (id:int) =
fun(x) -> "yam-yam"
I thought that I could add those function to my dictionary, but... Nothing of the sort! The following code:
FUNCTIONS.Add("unchanged", new FunctionDefinition<bool>(unchanged))
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
FUNCTIONS.Add("changed", new FunctionDefinition<bool>(changed))
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
FUNCTIONS.Add("dummy", new FunctionDefinition<string>(dummyfortesting))
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
gives unambiguous error messages:
// The type 'obj' does not match the type 'bool'
// The type 'obj' does not match the type 'bool'
// The type 'obj' does not match the type 'string'
whereas the following is true:
typeof<bool>.isSubclassOf(typeof<obj>) // -> true
It is unfair, isn't it?
The Question is
How to instantiate FUNCTIONS
dictionary to hold several FunctionDefinition<bool>
, FunctionDefinition<string>
instances?
or is there a solution other than keeping a generic FunctionDefinition
type for functions that return different types?
One solution is to pass the desired type as an argument to the constructor of FunctionDefinition
as follows:
type FunctionDefinition(typ:System.Type, exec:int->(Data.Reader->???)) =
member x.Exec = exec
member x.ReturnType = typ
But here it is unclear how to declare exec
.
I hope I was clear enough.
Thank you SO much.
Sincerely yours,
Kh
The dictionary you're creating needs to hold values of the same type. If you create two FunctionDefinition<'T>
values with different type argument, they will be different types, so they cannot be combined in a single dictionary.
One way to solve this is to define a non-generic interface and create a dictionary that stores values of this interface (which will be implemented by all generic FunctionDefinition<'T>
objects)
type IFunctionDefinition =
abstract ReturnType : System.Type
abstract Exec : int -> (Reader -> obj)
let dict = new Dictionary<string, IFunctionDefinition>()
The Exec
function has to return obj
, because there is no way to recover the type information after storing the function in a (homogeneous) dictionray. Your concrete type can then implement the interface:
type FunctionDefinition<'a>(exec:int->(Reader->'a)) =
member x.Exec = exec
interface IFunctionDefinition with
member x.ReturnType = typeof<'a>
member x.Exec n = fun rdr -> box (exec n rdr)
Now you can add created function definitions to the dictionary, because they implement the common interface:
let foo = FunctionDefinition<int>(fun _ _ -> 42)
dict.Add("foo", foo)
Another approach would be to make the type definition non-generic. You'll need to do some dynamic type tests when using the functions from the dictionary to figure out what value they return. You can make this explicit by using a discriminated union as the return type:
type ResultType =
| String of string
| Bool of bool
// etc. for all supported return types
精彩评论