简体   繁体   English

f#成员约束和IEnumerable集合

[英]f# member constraints and IEnumerable collections

I'm new to F# and today I saw the member constraint feature of F#. 我是F#的新手,今天我看到了F#的成员约束功能。

I was thinking of if one could (ab)use it in the following way... 我在考虑是否可以以下方式使用它...

Say I want to iterate get the texts of the items in a ListView. 说我想迭代获取ListView中的项目的文本。 I could do it like this: 我可以这样做:

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

The Seq.cast above is not type safe and kind of ugly. 上面的Seq.cast类型不安全且难看。

What I was thinking was this: 我当时在想的是:

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

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

So the type of the IEnumerable is in fact encoded into the class, just in a round-about way. 因此IEnumerable的类型实际上是以一种循环方式编码到该类中的。

The example of member constraints I saw was the following: 我看到的成员约束示例如下:

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)

I got the idea that it's a bit similar to what I'd want to do above. 我的想法是,它与我上面想要做的有点类似。

Could this be used to create a function to be use like the following instead? 可以使用它来创建一个如下所示使用的函数吗?

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

Edit : The idea was to implement a general Seq.asSeq extension method that'd take something that implements the non-generic IEnumerable and that has a strongly typed Item -member as above and then invoke Seq.cast with the corresponding type from the Item -member. 编辑 :当时的想法是实现一个通用Seq.asSeq那会拿东西,实现了非泛型扩展方法IEnumerable并具有强类型的Item -member如上,然后调用Seq.cast从相应类型Item -会员。

Here's my first fumbling attempts: 这是我的第一次摸索尝试:

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

This almost works, but not for the real type! 这几乎可以工作,但不适用于实际类型!

> 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'
>

I guess it's my fake-types that do not properly reflect the .NET indexed properties... 我猜这是我的假类型无法正确反映.NET索引属性...

Any help? 有什么帮助吗?

Edit 2: This actually works! 编辑2:这实际上有效!

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

It sounds like you want something along these lines , in which case your code is nearly right. 听起来您需要这些方面的东西,在这种情况下,您的代码几乎是正确的。

Note that one issue is that you're attempting to use indexed properties interchangeably with methods, but you're not doing it quite right: for an indexed property named Item , the method's actual name will be get_Item (alternatively, you can use the syntax member Item : int -> 'a with get instead of using the get_Item method directly). 请注意,一个问题是您试图与方法互换使用索引属性,但您做得并不正确:对于名为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