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}…
;我在想是否有办法保留这种功能。但无论如何,这可能不是一个好主意:)