开发者

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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜