F # Generics and Casting - PullRequest
       17

F # Generics and Casting

3 голосов
/ 06 апреля 2011

после прочтения всех вопросов, предложенных как связанные, я не смог найти ответ на свой вопрос.Пишу вам в надежде, что вы скоро ответите и снисходительно осудите мое отсутствие знаний в этой области.

У меня есть тип для включения определения функции:

type FunctionDefinition<'a>(exec:int->(Data.Reader->'a)) =
    member x.Exec = exec
    member x.ReturnType = typeof<'a>

Как выЗдесь можно увидеть, что exec должна быть функцией, которая принимает один аргумент int и возвращает другую функцию, которая принимает один аргумент Data.Reader и возвращает значение типа 'a (такая утомительная фраза!).Определение Data.Reader здесь неуместно.

Кроме того, у меня есть словарь для хранения string->FunctionDefinition пар следующим образом:

let FUNCTIONS = new Generic.Dictionary<string, FunctionDefinition<obj>>()

FunctionDefinition экземпляры в FUNCTIONS собираютсячтобы держать функции нескольких типов, и именно поэтому это FunctionDefinition<obj> (я считаю, что это корень зла, но я не могу избежать этого, поэтому я здесь).

Тогда у меня есть некоторые функции длябыть завернутым в 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"

Я думал, что смогу добавить эти функции в свой словарь, но ... Ничего подобного!Следующий код:

FUNCTIONS.Add("unchanged", new FunctionDefinition<bool>(unchanged))
                           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
FUNCTIONS.Add("changed", new FunctionDefinition<bool>(changed))
                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
FUNCTIONS.Add("dummy", new FunctionDefinition<string>(dummyfortesting))
                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

дает недвусмысленные сообщения об ошибках:

// 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'

, тогда как верно следующее:

typeof<bool>.isSubclassOf(typeof<obj>) // -> true

Это несправедливо, не так ли?


Вопрос:

Как создать FUNCTIONS словарь для хранения нескольких FunctionDefinition<bool>, FunctionDefinition<string> экземпляров?

или есть другое решение?чем хранить общий тип FunctionDefinition для функций, которые возвращают разные типы?


Одно из решений - передать требуемый тип в качестве аргумента конструктору FunctionDefinition следующим образом:

type FunctionDefinition(typ:System.Type, exec:int->(Data.Reader->???)) =
    member x.Exec = exec
    member x.ReturnType = typ

Но здесь неясно, как объявить exec.

Надеюсь, я был достаточно ясен.

Большое спасибо.

С уважением,

Х

1 Ответ

5 голосов
/ 06 апреля 2011

Словарь, который вы создаете, должен содержать значения одного типа.Если вы создадите два FunctionDefinition<'T> значения с аргументом другого типа, они будут разных типов, поэтому их нельзя объединить в одном словаре.

Один из способов решения этого - определитьнеуниверсальный интерфейс и создать словарь, в котором хранятся значения этого интерфейса (который будет реализован всеми универсальными FunctionDefinition<'T> объектами)

type IFunctionDefinition =
  abstract ReturnType : System.Type
  abstract Exec : int -> (Reader -> obj)

let dict = new Dictionary<string, IFunctionDefinition>()

Функция Exec должна возвращать obj, посколькуневозможно восстановить информацию о типе после сохранения функции в (однородном) словаре.Ваш конкретный тип может затем реализовать интерфейс:

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)

Теперь вы можете добавить созданные определения функций в словарь, поскольку они реализуют общий интерфейс:

let foo = FunctionDefinition<int>(fun _ _ -> 42)
dict.Add("foo", foo)

Другой подход будет означать, что определение типа не является универсальным.Вам нужно будет выполнить несколько тестов динамического типа при использовании функций из словаря, чтобы определить, какое значение они возвращают.Вы можете сделать это явным образом, используя различаемый союз в качестве возвращаемого типа:

type ResultType =
  | String of string
  | Bool of bool
  // etc. for all supported return types
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...