2016-06-07 53 views
2

給出你如何定義這個靜態解析的類型參數?

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能夠在任何具有匹配方法簽名的方法上調用該方法?

回答

4

我認爲這裏的一些難點是由於CheckCanExecute被定義爲咖喱函數而引起的。對於成員來說,使用tupled函數可能會更好(curried函數的編譯方式比較棘手,可能會混淆靜態解析的約束)。

如果更改RelayCommand成員如下:

member x.CheckCanExecute (sender:obj, eventArgs:EventArgs) = 
    event.Trigger([| sender;eventArgs |]) 

,使您的checkCanExecuteinline功能,需要tupled功能:

let inline checkCanExecute (e:^a) = 
    (^a: (member CheckCanExecute: obj * EventArgs -> unit) (e, box me,(EventArgs()))) 

那麼下面的類型檢查:

checkCanExecute me 
+0

這樣的話,你不能使用咖喱職能與SRTP? – Maslow

+0

@Maslow:你可以,但你需要以不尋常的方式寫出來。我添加了一個替代答案。 – piaste

4

如果你想使用SRTPs,你不能以普通的方式來使用方法。成員調用語法無法一次處理多個curried參數。

您可以使用.NET風格的元組聲明,正如Tomas所說,或者您必須明確寫出member x.f a = fun b -> fun c -> ...的形式。

在您的例子,這將意味着:

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() 
+0

不錯!我無法弄清楚如何使這項工作:) –

+0

這似乎仍然需要編輯目標方法(S)?但距離更近一步。 – Maslow