2

我写了一个这样的函数

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().

有没有一条干净的方法可以让我从上面的管道元件中得到一些东西?

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

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

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

4

2 回答 2

4

我们利用Seq.filter并且Seq.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.map和的系列更改Seq.filterSeq.choose

Seq.choose (fun ra -> match box ra.Member with
                      | :? SPUser -> Some (l.Title, ra.Member.LoginName.ToLower())
                      | _ -> None)
于 2012-09-26T09:06:19.100 回答
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(instead of filter)、for(instead of collect) 等。另外,我认为它更适合编写嵌套操作(您需要在这里将变量保持在范围内),因为它仍然具有很强的可读性并保持熟悉的代码结构。

于 2012-09-26T12:42:58.313 回答