简体   繁体   English

在 F# 中将枚举转换为列表或序列或泛型集合类型

[英]converting an enum to a list or sequence or generic collection type in F#

I have a type that is either a Dictionary<string,Node<'a>>*Edge<'a> list or a ConcurrentDictionary<string,Node<'a>>*Edge<'a> list .我有一个类型是Dictionary<string,Node<'a>>*Edge<'a> listConcurrentDictionary<string,Node<'a>>*Edge<'a> list I am trying to create a get_nodes function, but when I call .Values from the Dictionary and the ConcurrentDictionary , the functions return different types!我正在尝试创建一个get_nodes函数,但是当我从DictionaryConcurrentDictionary调用.Values时,这些函数返回不同的类型!

So I need to somehow convert both of the types into the same type for F# to compile...所以我需要以某种方式将这两种类型转换为相同的类型,以便 F# 编译...

The type given by Dictionary.Values is Dictionary'2.ValueCollection<string,Node<'a>> while the type yielded by ConcurrentDictionary is ICollection<Node<'a>> . Dictionary.Values给出的类型是Dictionary'2.ValueCollection<string,Node<'a>>ConcurrentDictionary产生的类型是ICollection<Node<'a>>

I figured out that both types have a "GetEnumerator()" function.我发现这两种类型都有一个“GetEnumerator()”函数。 What I need to do is somehow turn the enumerator into a seq or list, etc.我需要做的是以某种方式将枚举器转换为 seq 或列表等。

Here is my code:这是我的代码:

   static member get_nodes (g:Graph<'a>) = 
        match g with 
        | Dictionary_Graph(nd,el) -> let n = nd.Values
                                     let enum = n.GetEnumerator()


        | ConcurrentDictionary_Graph(nd,el) -> let n = nd.Values
                                               let enum = n.GetEnumerator()

How do I pull the data out of the enum variable?如何从枚举变量中提取数据?

You are probably used to C# which would auto upcast the ValueCollection to an ICollection (which ValueCollection implements).您可能已经习惯了 C#,它会自动将 ValueCollection 向上转换为 ICollection(ValueCollection 实现)。 F# does not do this, so you must manually cast the result of Dictionary.Values to ICollection. F# 不会这样做,因此您必须手动将 Dictionary.Values 的结果转换为 ICollection。

let n = nd.Values :> ICollection<Node<'a>>

Full method would look something like this:完整方法看起来像这样:

static member get_nodes (g:Graph<'a>) = 
    match g with 
    | Dictionary_Graph(nd,el) ->
        nd.Values :> ICollection<Node<'a>>
    | ConcurrentDictionary_Graph(nd,el) ->
        nd.Values

From what I understand, F# does not auto-upcast because of the way that the auto type inference engine works.据我了解,由于自动类型推理引擎的工作方式,F# 不会自动向上转换。 It's irritating when you're used to C#, but it's a price worth paying to get automatic type inferencing.当您习惯了 C# 时,这很烦人,但为了获得自动类型推断而付出的代价是值得的。 Also consider that in C#, you would have to specify the return type up front on the method, which makes it easy for C# to do the cast for you.还要考虑到,在 C# 中,您必须在方法的前面指定返回类型,这使得 C# 可以轻松地为您进行转换。 F# engine infers the return type based on what you actually return, so the safest thing is to not make assumptions about how you want it cast. F# 引擎根据您实际返回的内容推断返回类型,因此最安全的做法是不要假设您希望它如何转换。

Not general consensus, but my opinion: I hope they will add auto upcasting of return values for specific cases (like output type is declared ahead of time or to make branches conform like above), but it's a minor irritation for now.不是普遍共识,但我的意见是:我希望他们会为特定情况添加返回值的自动向上转换(例如提前声明输出类型或使分支符合上述要求),但现在这是一个小问题。

Update (from question in comments)更新(来自评论中的问题)

ICollection<T> should now be directly usable as a sequence since it implements IEnumerable<T> . ICollection<T>现在应该可以直接用作序列,因为它实现了IEnumerable<T> In this case auto-upcasting actually does work.在这种情况下,自动向上转换实际上确实有效。 :) :)

myGraph
|> Graph.get_nodes 
|> Seq.iter (fun x -> printfn "%A" x)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM