F#Pipelines从上面的管道阶段访问数据

时间:2012-09-26 08:49:28

标签: f#

我写了一个像这样的函数

let GetAllDirectAssignmentsforLists (spWeb : SPWeb) =    
  spWeb.Lists 
  |> Seq.cast<SPList> 
  |> Seq.filter(fun l -> l.HasUniqueRoleAssignments) 
  |> Seq.collect (fun l -> l.RoleAssignments 
                           |> Seq.cast<SPRoleAssignment> 
                           |> Seq.map(fun ra -> ra.Member)
                 )
  |> Seq.filter (fun p -> p.GetType().Name = "SPUser")
  |> Seq.map(fun m -> m.LoginName.ToLower())

我想返回一个元组,其中包含发送管道中的列表名称(取自l.Title)和m.LoginName.ToLower()

我是否有从上述管道元件中获取物品的净化道?

一种方法是在管道的第二阶段中对返回值进行元组,然后将标题一直向下传递....但是这将污染代码,所有后续阶段将必须接受并返回元组价值只是为了获得价值的最后阶段。

我想知道是否有一种干净简单的方法....

此外,在管道(fun p -> p.GetType().Name = "SPUser")的第4阶段,我可以使用,如果在这里比较类型?而不是将typename转换为string然后匹配字符串?

2 个答案:

答案 0 :(得分:4)

我们利用Seq.filterSeq.map可以在Seq.collect内推送而不更改结果的事实。在这种情况下,l仍可供访问。

最后一个filter函数更适合与type test operator :?一起使用。

let GetAllDirectAssignmentsforLists(spWeb: SPWeb) =    
    spWeb.Lists 
    |> Seq.cast<SPList> 
    |> Seq.filter (fun l -> l.HasUniqueRoleAssignments) 
    |> Seq.collect (fun l -> l.RoleAssignments 
                             |> Seq.cast<SPRoleAssignment> 
                             |> Seq.map (fun ra -> ra.Member)
                             |> Seq.filter (fun p -> match box p with
                                                     | :? SPUser -> true
                                                     | _ -> false)
                             |> Seq.map (fun m -> l.Title, m.LoginName.ToLower()))

为了进一步简化,您可以将Seq.mapSeq.filter系列更改为Seq.choose

Seq.choose (fun ra -> match box ra.Member with
                      | :? SPUser -> Some (l.Title, ra.Member.LoginName.ToLower())
                      | _ -> None)

答案 1 :(得分:3)

虽然您可以通过解除collect中的其余计算来解决问题,但我认为您可以通过使用序列表达式而不是流水线来使代码更具可读性。

我无法运行代码来测试它,但这应该是等效的:

let GetAllDirectAssignmentsforLists (spWeb : SPWeb) = seq {
  // Corresponds to your 'filter' and 'collect'
  for l in Seq.cast<SPList> spWeb.Lists do
    if l.HasUniqueRoleAssignments then
      // Corresponds to nested 'map' and 'filter'
      for ra in Seq.cast<SPRoleAssignment> l.RoleAssignments do
        let m = ra.Member
        if m.GetType().Name = "SPUser" then 
          // This implements the last 'map' operation
          yield l.Title, m.LoginName.ToLower() }

上面的代码与@pad的版本更接近于原始代码,因为其余的计算嵌套在for下(对应于collect下的嵌套),所以你可以查看已经在范围内的所有变量 - 例如您需要的l

关于序列表达式的好处是,您可以使用F#构造,如if(而不是filter),for(而不是collect)等。此外,我认为它更适合编写嵌套操作(这里需要将变量保留在范围内),因为它仍然具有可读性并且保持熟悉的代码结构。