简体   繁体   English

F#泛型和铸造

[英]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!). 正如你在这里看到的, exec应该是一个函数,它接受一个int参数并返回另一个函数,该函数接受一个Data.Reader参数并返回一个类型为'a的值(这样一个令人筋疲力尽的短语!)。 The definition of Data.Reader is irrelevant here. Data.Reader的定义与此无关。

Also, I have a dictionary to keep string->FunctionDefinition pairs as follows: 另外,我有一个字典来保持string->FunctionDefinition对,如下所示:

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). FUNCTIONS中的FunctionDefinition实例将保存几种类型的函数,这就是为什么它是FunctionDefinition<obj> (我相信这是邪恶的根源,但我无法避免这种情况,所以我在这里)。

Then I have some functions to be wrapped in FunctionDefinition and put into FUNCTIONS : 然后我将一些函数包装在FunctionDefinition并放入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? 如何实例化FUNCTIONS字典以容纳多个FunctionDefinition<bool>FunctionDefinition<string>实例?

or is there a solution other than keeping a generic FunctionDefinition type for functions that return different types? 或者除了为返回不同类型的函数保留通用FunctionDefinition类型之外,还有其他解决方案吗?


One solution is to pass the desired type as an argument to the constructor of FunctionDefinition as follows: 一种解决方案是将所需类型作为参数传递给FunctionDefinition的构造FunctionDefinition ,如下所示:

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 . 但是现在还不清楚如何宣布exec

I hope I was clear enough. 我希望我很清楚。

Thank you SO much. 非常感谢。

Sincerely yours, 您忠诚的,

Kh 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. 如果使用不同的类型参数创建两个FunctionDefinition<'T>值,它们将是不同的类型,因此它们不能组合在单个字典中。

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) 解决此问题的一种方法是定义非泛型接口并创建一个存储此接口值的字典(将由所有通用FunctionDefinition<'T>对象实现)

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. Exec函数必须返回obj ,因为在(同类)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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM