簡體   English   中英

f#成員約束和IEnumerable集合

[英]f# member constraints and IEnumerable collections

我是F#的新手,今天我看到了F#的成員約束功能。

我在考慮是否可以以下方式使用它...

說我想迭代獲取ListView中的項目的文本。 我可以這樣做:

let listView = new System.Windows.Forms.ListView()
let itemTexts = 
    listView.Items
    |> Seq.cast<System.Windows.Forms.ListViewItem>
    |> Seq.map (fun item -> item.Text)

上面的Seq.cast類型不安全且難看。

我當時在想的是:

> let item (i:int) = listView.Items.Item i;;

val item : int -> System.Windows.Forms.ListViewItem

因此IEnumerable的類型實際上是以一種循環方式編碼到該類中的。

我看到的成員約束示例如下:

type Cat() = 
    member this.Walk() = printfn "cat walk"
type Dog() = 
    member this.Walk() = printfn "dog walk"

let adapter() = 
    let cat = Cat()
    let dog = Dog()
    let inline walk (x : ^T) = (^T : (member Walk : unit->unit) (x))
    walk(cat)
    walk(dog)

我的想法是,它與我上面想要做的有點類似。

可以使用它來創建一個如下所示使用的函數嗎?

let itemTexts = 
    listView.Items
    |> Seq.asSeq
    |> Seq.map (fun item -> item.Text)

編輯 :當時的想法是實現一個通用Seq.asSeq那會拿東西,實現了非泛型擴展方法IEnumerable並具有強類型的Item -member如上,然后調用Seq.cast從相應類型Item -會員。

這是我的第一次摸索嘗試:

let listView = new System.Windows.Forms.ListView()
let items = 
    listView.Items

type cat() = 
    member this.Item (i:int) = "cat walk"
    interface System.Collections.IEnumerable with
       member this.GetEnumerator() = ((seq { yield (this.Item 0) }) :> System.Collections.IEnumerable).GetEnumerator()

type dog() = 
    member this.Item (i:int) = 6
    interface System.Collections.IEnumerable with
       member this.GetEnumerator() = ((seq { yield (this.Item 0) }) :> System.Collections.IEnumerable).GetEnumerator()

let cat = cat()
let dog = dog()

let inline asSeq (x : ^t) =
    let dummy _ = (^t : (member Item : int -> 'a) (x, 0))
    Seq.cast<'a> x

這幾乎可以工作,但不適用於實際類型!

> cat;;
val it : cat = seq ["cat walk"]
> asSeq cat;;
val it : seq<string> = seq ["cat walk"]
> asSeq dog;;
val it : seq<int> = seq [6]
> asSeq items;;

  asSeq items;;
  ------^^^^^

C:\...\stdin(5,7): error FS0001: The type 'System.Windows.Forms.ListView.ListViewItemCollection' does not support any operators named 'Item'
>

我猜這是我的假類型無法正確反映.NET索引屬性...

有什么幫助嗎?

編輯2:這實際上有效!

let inline asSeq (x : ^t) =
    let dummy _ = (^t : (member Item : int -> 'a with get) (x, 0))
    Seq.cast<'a> x

聽起來您需要這些方面的東西,在這種情況下,您的代碼幾乎是正確的。

請注意,一個問題是您試圖與方法互換使用索引屬性,但您做得並不正確:對於名為Item的索引屬性,該方法的實際名稱將為get_Item (或者,您可以使用語法member Item : int -> 'a with get而不是直接使用get_Item方法)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM