Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Generics 如何在运行时实例化F#中的泛型类型?_Generics_F# - Fatal编程技术网

Generics 如何在运行时实例化F#中的泛型类型?

Generics 如何在运行时实例化F#中的泛型类型?,generics,f#,Generics,F#,我希望我能做到以下几点: type Logger = { warn : System.Type -> string -> unit // also methods for error, info etc } // during application startup let warn (serviceProvider : IServiceProvider) (t : Type) s = let loggerType = typeof<ILogger&l

我希望我能做到以下几点:

type Logger = {
    warn : System.Type -> string -> unit
    // also methods for error, info etc
}

// during application startup
let warn (serviceProvider : IServiceProvider) (t : Type) s =
    let loggerType = typeof<ILogger<'a>>.MakeGenericType(t)
    let logger = serviceProvider.GetService(loggerType) :?> ILogger
    logger.LogWarning(s)

let log = { warn = warn; ... } // with similar setups for info, error etc
它将使用类型
Foo
记录一条消息,以确定错误

麻烦的表达是

typeof<ILogger<'a>>.MakeGenericType(t)
但是
typeof
不能用F#编译

我如何实例化这样一个泛型类型,其中类型参数只在运行时才知道,在F#?

中,C中的F#等价于
typeof(ILogger)
是使用
typedeof
函数:

typedefof<ILogger<_>>.MakeGenericType(t)
typedefof.MakeGenericType(t)
这仍然是一个采用完全实例化类型的正常函数。
占位符将自动填充
obj
,但
typedefof
函数不返回类型,而是返回其泛型类型定义。您也可以通过对
typeof
的结果调用
GetGenericTypeDefinition
来执行相同的操作,但是
typedefof
是一个更好的快捷方式

C语言中的
typeof(ILogger)
的F#等价物是使用
typedefof
功能:

typedefof<ILogger<_>>.MakeGenericType(t)
typedefof.MakeGenericType(t)

这仍然是一个采用完全实例化类型的正常函数。
占位符将自动填充
obj
,但
typedefof
函数不返回类型,而是返回其泛型类型定义。您也可以通过对
typeof
的结果调用
GetGenericTypeDefinition
来执行相同的操作,但是
typedefof
是一个更好的快捷方式

您要查找的语法是
typedefof
——它将为您提供非实例化类型
iLoger
,然后您可以在该类型上调用
MakeGenericType

然而,我宁愿建议您重新思考您的体系结构。为什么在运行时实例化类型?这样比较慢,也不太安全。在这种情况下,我认为没有理由这样做

最好将类型作为泛型参数传递。当然,不能让记录成员是泛型函数,所以这是一个糟糕的问题。然而,F#确实为这类事情提供了另一种工具——接口。接口方法可以是完全通用的:

type Logger =
    abstract member warn<'logger> : string -> unit

let mkLog (serviceProvider : IServiceProvider) =
    { new Logger with
        member warn<'logger> s =
            let logger = serviceProvider.GetService(typeof<ILogger<'logger>>) :?> ILogger
            logger.LogWarning(s)
    }

let log = mkLog serviceProvider

// usage:
log.warn<Foo> "a warning message"
类型记录器=
抽象成员=

让logger=serviceProvider.GetService(typeof您要查找的语法是
typedefof
——它将为您提供非实例化类型
iLoger
,然后您可以在该类型上调用
MakeGenericType

但是,我建议您重新考虑您的体系结构。为什么要在运行时实例化类型?这样会更慢、更不安全。在这种情况下,我认为没有理由这样做

最好将您的类型作为泛型参数传递。当然,您不能让记录成员成为泛型函数,因此这很糟糕。但是,F#确实为这类事情提供了另一种工具-接口。接口方法可以是完全泛型的:

type Logger =
    abstract member warn<'logger> : string -> unit

let mkLog (serviceProvider : IServiceProvider) =
    { new Logger with
        member warn<'logger> s =
            let logger = serviceProvider.GetService(typeof<ILogger<'logger>>) :?> ILogger
            logger.LogWarning(s)
    }

let log = mkLog serviceProvider

// usage:
log.warn<Foo> "a warning message"
类型记录器=
抽象成员=

让logger=serviceProvider.GetService(typeoftanks!通过包含关于我的设计的比绝对必要的更多细节,我实际上希望有人能提出更好的设计;)接口方法缺乏解构的能力,但是-您知道我是否可以使用模式匹配?自定义匹配器(也称为“活动模式”)解构使用此方法创建的记录器?在我知道你想要做什么之前,我不能说任何有意义的话。是的,一个活动模式可能会起作用。在使用接口而不是日志记录之前,我像
doSomeStuff{warn=warn}一样解构…
在一些地方的方法签名中;我在想是否有办法保留该功能。但这可能不是一个好主意:)谢谢!通过包含比绝对必要的更多关于我的设计的细节,我实际上希望有人能提出更好的设计;)接口方法缺乏解构的能力,但是-您知道我是否可以使用模式匹配?自定义匹配器(也称为“活动模式”)解构使用此方法创建的记录器?在我知道你到底想做什么之前,我不能说任何明智的话。是的,一个积极的模式可能会起作用。在使用一个接口而不是日志记录之前,我在一些地方解构方法签名中的
doSomeStuff{warn=warn}…
;我在想是否有办法保留这种功能。但无论如何,这可能不是一个好主意:)