- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
这是一个假设场景。
我有很多用户名(比如 10,000,000,000,000,000,000,000。是的,我们正处于星际时代 :))。每个用户都有自己的数据库。我需要遍历用户列表并对每个数据库执行一些 SQL 并打印结果。
因为我学到了函数式编程的优点,并且因为我要与如此多的用户打交道,所以我决定使用 F# 和纯序列(又名 IEnumerable)来实现它。我走了。
// gets the list of user names
let users() : seq<string> = ...
// maps user name to the SqlConnection
let mapUsersToConnections (users: seq<string>) : seq<SqlConnection> = ...
// executes some sql against the given connection and returns some result
let mapConnectionToResult (conn) : seq<string> = ...
// print the result
let print (result) : unit = ...
// and here is the main program
users()
|> mapUsersToConnections
|> Seq.map mapConnectionToResult
|> Seq.iter print
漂亮吗?优雅的?绝对。
但是! 谁以及在什么时候处理 SqlConnections?
而且我不认为 mapConnectionToResult
应该做的答案 是正确的,因为它对给定的连接的生命周期一无所知。根据 mapUsersToConnections
的实现方式和各种其他因素,事情可能会起作用或不起作用。
由于 mapUsersToConnections
是唯一可以访问连接的其他地方,因此它必须负责处理 SQL 连接。
在 F# 中,可以这样做:
// implementation where we return the same connection for each user
let mapUsersToConnections (users) : seq<SqlConnection> = seq {
use conn = new SqlConnection()
for u in users do
yield conn
}
// implementation where we return new connection for each user
let mapUsersToConnections (users) : seq<SqlConnection> = seq {
for u in users do
use conn = new SqlConnection()
yield conn
}
C# 等价物是:
// C# -- same connection for all users
IEnumerable<SqlConnection> mapUsersToConnections(IEnumerable<string> users)
{
using (var conn = new SqlConnection())
foreach (var u in users)
{
yield return conn;
}
}
// C# -- new connection for each users
IEnumerable<SqlConnection> mapUsersToConnections(IEnumerable<string> user)
{
foreach (var u in users)
using (var conn = new SqlConnection())
{
yield return conn;
}
}
我执行的测试表明对象确实在正确的点被正确处理,即使并行执行的东西也是如此:一次在共享连接的整个迭代结束时;在非共享连接的每个迭代周期之后。
那么,问题:我做对了吗?
编辑:
有些回答友善地指出了代码中的一些错误,我也做了一些修正。编译的完整工作示例如下。
SqlConnection 的使用仅用于示例目的,它实际上是任何 IDisposable。
编译示例
open System
// Stand-in for SqlConnection
type SimpeDisposable() =
member this.getResults() = "Hello"
interface IDisposable with
member this.Dispose() = printfn "Disposing"
// Alias SqlConnection to our dummy
type SqlConnection = SimpeDisposable
// gets the list of user names
let users() : seq<string> = seq {
for i = 0 to 100 do yield i.ToString()
}
// maps user names to the SqlConnections
// this one uses one shared connection for each user
let mapUsersToConnections (users: seq<string>) : seq<SqlConnection> = seq {
use c = new SimpeDisposable()
for u in users do
yield c
}
// maps user names to the SqlConnections
// this one uses new connection per each user
let mapUsersToConnections2 (users: seq<string>) : seq<SqlConnection> = seq {
for u in users do
use c = new SimpeDisposable()
yield c
}
// executes some "sql" against the given connection and returns some result
let mapConnectionToResult (conn:SqlConnection) : string = conn.getResults()
// print the result
let print (result) : unit = printfn "%A" result
// and here is the main program - using shared connection
printfn "Using shared connection"
users()
|> mapUsersToConnections
|> Seq.map mapConnectionToResult
|> Seq.iter print
// and here is the main program - using individual connections
printfn "Using individual connection"
users()
|> mapUsersToConnections2
|> Seq.map mapConnectionToResult
|> Seq.iter print
结果是:
共享连接:“你好”“你好”...“处置”
个别连接:“你好”“处置”“你好”“处置”
最佳答案
我会避免这种方法,因为如果你的库的不知情用户做了类似的事情,结构就会失败
users()
|> Seq.map userToCxn
|> Seq.toList() //oops disposes connections
|> List.map .... // uses disposed cxns
. . ..
我不是这个问题的专家,但我认为最好的做法是不要让序列/IEnumerables 在它们产生它们之后弄乱它们,因为中间的 ToList() 调用会产生不同的结果而不是直接作用于序列——DoSomething(GetMyStuff()) 将不同于 DoSomething(GetMyStuff().ToList())。
实际上,为什么不对整个事情使用序列表达式,因为这样可以完全解决这个问题:
seq{ for user in users do
use cxn = userToCxn user
yield cxnToResult cxn }
(其中 userToCxn 和 cxnToResult 都是简单的一对一非处置函数)。这似乎比任何东西都更具可读性,应该会产生预期的结果,可并行化,并且适用于任何一次性用品。这可以使用以下技术转换为 C# LINQ:http://solutionizing.net/2009/07/23/using-idisposables-with-linq/
from user in users
from cxn in UserToCxn(user).Use()
select CxnToResult(cxn)
不过,另一种做法是先定义“getSomethingForAUserAndDisposeTheResource”函数,然后将其用作基本构建 block :
let getUserResult selector user =
use cxn = userToCxn user
selector cxn
一旦有了这个,就可以轻松地从那里开始构建:
//first create a selector
let addrSelector cxn = cxn.Address()
//then use it like this:
let user1Address1 = getUserResult addrSelector user1
//or more idiomatically:
let user1Address2 = user1 |> getUserResult addrSelector
//or just query dynamically!
let user1Address3 = user1 |> getUserResult (fun cxn -> cxn.Address())
//it can be used with Seq.map easily too.
let addresses1 = users |> Seq.map (getUserResult (fun cxn -> cxn.Address()))
let addresses2 = users |> Seq.map (getUserResult addrSelector)
//if you are tired of Seq.map everywhere, it's easy to create your own map function
let userCxnMap selector = Seq.map <| getUserResult selector
//use it like this:
let addresses3 = users |> userCxnMap (fun cxn -> cxn.Address())
let addresses4 = users |> userCxnMap addrSelector
如果您只需要一个用户,那么您就不必致力于检索整个序列。我想这里吸取的教训是让你的核心功能变得简单,这样可以更容易地在它之上构建抽象。请注意,如果您在中间某处执行 ToList,这些选项都不会失败。
关于c# - IEnumerable<IDisposable> : who disposes of what and when -- Did I get it right?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6778958/
我有一个 Segment 类和一个这样的段数组: private static class Segment { int number, type; Segment(in
我在 SO 中看到一些创建 multilanguage websites in JavaScript 的好建议包括 this article on JavaScript internationaliz
我们有浏览器前缀或黑客 (for Google and Safari) text-align: -webkit-right; (for Firefox) text-align:
过去几天我一直在关注这个问题,我正处于需要寻求帮助的地步。 http://cub.northnodes.com/index.php/about/mission/ 我需要立即捐赠 列一直 float 到
When I press right ctrl, I want the right shift the text will align right. When I press left ctrl le
我已经将右侧的列拆分为顶部和底部。在每个部分中,我在执行以下操作时遇到问题:我希望顶部占据左列高度的 50%,底部占据左列高度的另外 50%。 +-------------------+-------
我知道这个问题的标题很糟糕。对不起。 我有四个 div similar to this .我想要做的只是让 div 编号 2 和 4 之间的垂直空间被删除,而不改变 HTML 的结构。是否可以仅使用
我将表格设置为 100% 宽度。我会添加一个带有 php 的随机 div,有时会充满广告。我希望广告 div 位于表格的右侧和内容。我希望表格位于左侧,但仍为 100% 左右,它将填充广告 div 左
这个问题在这里已经有了答案: Bootstrap align navbar items to the right (24 个答案) 关闭 5 年前。
.floatright { float: right;margin: 0 0 10px 10px;clear: right;width:60px; height:60px; } Lorem
我正在尝试将 td 中的某些内容右对齐。 align="right"有效,但 text-align:right 无效。这是一个 jsfiddle显示这两种情况的示例。除了右对齐右列外,这两种情况是相同
在设计网站时,您认为用于特定任务的最佳图像格式是什么? 在试图找出用于特定任务的格式时,我总是发现自己处于两难境地……例如,我应该全面使用 .jpg 吗?或者,我何时以及为什么应该使用 .png? 例
我是一个 MySQL 新手,今天我尝试设置一个超过 5 行的 MySQL 调用。我不断收到语法错误,我尝试修复了几个小时,但我不知道问题出在哪里。这是代码: USE myDatabase; DELIM
这让我发疯。我有一个 div float 到另一个 div 的右侧,如下所示: Current Membership: 我有以下 css 规则: div#container { f
我有以下代码片段,它会产生不需要的“填充”区域,而填充为零。如何避免这个区域? 代码 div.left { background-color: red; max-width: 25%; f
在 C++ 中,表达式 left() = right() 求值 right() left() 按那个顺序。 right() 先行,正如已讨论过的 here. 我想不出让 right() 先走的理由。你
我有一个很小的菜单列表,当鼠标靠近时它应该会增长。在其原始状态下,菜单是右对齐的,悬停时每第二个元素向右移动并左对齐以为增加的高度腾出空间(参见 JSFiddle )。 ul { font-siz
td.myclass{ width: 6em; text-align: right; padding-right: 2em; } 如您所见,我希望单元格中的文本右对齐,距离单元
你怎么能看到 http://jsfiddle.net/73wst/ 我想在停止下开始,但我不知道如何设置它的样式。 我的 HTML: Stop Start 我的 CSS: .sta
一个大的内部 div 在一个小的外部 div 中,并且外部 div 溢出自动。但是为什么没有内部 div margin-right 和外部 div padding-right? html
我是一名优秀的程序员,十分优秀!