给定的
open System
open System.Windows
open System.Windows.Input
open System.ComponentModel
type RelayCommand (canExecute:(obj -> bool), action:(obj -> unit)) =
let event = new DelegateEvent<EventHandler>()
interface ICommand with
[<CLIEvent>]
member x.CanExecuteChanged = event.Publish
member x.CanExecute arg = canExecute(arg)
member x.Execute arg = action(arg)
member x.CheckCanExecute (sender:obj) (eventArgs:EventArgs) = event.Trigger([| sender;eventArgs |])
如何编写静态解析的类型参数化函数,以满足对CheckCanExecute
的调用?
虽然这个功能有效,但它无法帮助我学习静态解析的类型参数语法
let checkCanExecute (c:RelayCommand) = c.CheckCanExecute (box this) (EventArgs())
我希望这可以工作
let checkCanExecute (e:^a) = (^a: (member CheckCanExecute: sender:obj -> EventArgs -> unit ) (e, (box me),(EventArgs())))
但是在呼叫现场
checkCanExecute addCommand
我得到方法或对象构造函数'CheckCanExecute'未找到(当使用第二个定义时,第一个编译就好了)
如何定义类let
绑定(或成员绑定,如果这是更好的完成工作的方法),使用Statically Resolved Type Parameters能够在任何具有匹配方法签名?
答案 0 :(得分:5)
如果你想使用SRTP,你不能用普通的方式来理解方法。成员调用语法无法一次处理多个curried参数。
要么像Tomas建议的那样使用.NET风格的tupled声明,要么你必须以member x.f a = fun b -> fun c -> ...
形式明确写出currying。
在你的例子中,这意味着:
type RelayCommand
// ...
member x.CheckCanExecute sender = fun eventArgs ->
event.Trigger([| sender;eventArgs |])
let inline checkCanExecute (e:^a) =
(^a: (member CheckCanExecute: obj -> (EventArgs -> unit)) (e, (box e)) ) <| EventArgs()
答案 1 :(得分:4)
我认为这里的一些困难是因为CheckCanExecute
被定义为一个curried函数。对于成员来说,使用tupled函数可能会更好(编译curried函数的方式很棘手,并且可能会使静态解析的约束混乱)。
如果您按以下方式更改RelayCommand
成员:
member x.CheckCanExecute (sender:obj, eventArgs:EventArgs) =
event.Trigger([| sender;eventArgs |])
并使您的checkCanExecute
inline
函数需要使用tupled函数:
let inline checkCanExecute (e:^a) =
(^a: (member CheckCanExecute: obj * EventArgs -> unit ) (e, box me,(EventArgs())))
然后进行以下类型检查:
checkCanExecute me