这里有一个小问题,关于为什么在我想出的最终答案中需要向上转换(在此底部);还有一个关于我是否只是想念“房间里的大象”的宏观问题:一些非常明显简洁的方式来做我想做的事[请不要问我-为什么-我想要我想要的;只是把它当作我想要这个的给定,它是......]
我想通过 MongoDB.Bson CLR 组件从 F# 初始化一个 BsonDocument。我认为我应该使用的 BsonDocument 构造函数的特定重载是
MongoDB.Bson.BsonDocument.BsonDocument(IDictionary<string,object>)
这就是为什么我认为这是我应该使用的(以下是在类型花园中漫步......)
来自 MongoDB 站点MongoDB CSharp Driver Tutorial的 C# 示例使用集合初始化器语法,该语法映射到 BsonDocument 公开的接口上的一个或多个 .Add 调用。教程示例类似于以下内容:
var bdoc = new BsonDocument { { "a", "1" }, { "b", "2" }, };
我不肯定正在使用 .Add 的哪个重载(并且不知道如何在 Visual Studio 中检查),但是所有基于字典的重载都输入为 <string, object>。在这种情况下,每对中的第二个值,即字符串类型的“1”和“2”,自动(通过继承)也是对象类型,所以一切正常。.Add 的其他重载要求第二项的类型为 BsonValue,这是 BsonString 的抽象超类型,无论使用哪种重载,它都具有从 .NET 字符串的隐式转换;所以那里也一切正常。调用构造函数的哪个重载并不重要。
这有点难以操作到 F# 等效项,因为很难使用 BsonDocument 的 .Add 方法。我想到了
[("a", "1");("b", "2");] |> Seq.iter BsonDocument.Add
但这不起作用,因为 BsonDocument.Add 不是静态方法;我可以实例化 BsonDocument,然后编写一个有趣的 lambda,它调用 BsonDocument 的 .Add 方法,这至少可以将可变性隔离开来:
[("a", "1");("b", "2");] |> Seq.fold ...
但事实证明这非常难看,因为需要在 BsonDocument 上使用显式类型表示法很有趣,因为引用 BsonDocument 的变量出现在 (new BsonDocument()) 之前,所以从左到右的类型推断不会有足够的信息(还),并且因为乐趣(至少,显然)没有办法知道它应该为每对中的第二个值访问从字符串到 BsonString 的隐式转换......
let bdoc = [("a","1");("b","2");] |> Seq.fold (fun (doc:BsonDocument) pair -> doc.Add(fst pair, new BsonString(snd pair))) (new BsonDocument())
...无论如何,我想,我会使用构造函数的更大重载
BsonDocument(IDictionary<string, object>)
但这是被迫的:
let bdoc = (new BsonDocument(dict
[("a", "1" :> Object);
("b", "2" :> Object);
]))
如果我取出上调
:> Object
然后 F# 抱怨它找不到 BsonDocument 的重载。
(在花园里漫步结束了......)
毕竟,微观问题是为什么在 F# 中,它不能弄清楚输入字典中的“1”和“2”是对象,从而找到适当的重载?
更大的宏观问题是我是否错过了在 F# 中执行此操作的适当、最佳实践、超酷、简洁的方法?