与ref传递的参数互操作

时间:2016-11-18 15:34:08

标签: c# f# interop mutable ref

我试图调用现有库的C#函数(我没有时间将整个库移植到F#)

namespace ExportLib
{

    public static class Xlsx
    {
        public static bool TestSave(string proposed, ref string filename, ref string save_log) {

来自F#代码

let getUserFile(proposed) : UserFile =
   let mutable filename = ""
   let mutable save_log = ""
   match Xlsx.TestSave(proposed, ref filename, ref save_log) with
   | true -> FileResult(filename)
   | false -> ErrorMsg(save_log)

意味着将函数转换为代数数据类型,目的是使非法状态unrepresentable

type UserFile =
  // The value here is the file path.
| FileResult of string
  // The value here is the error msg.
| ErrorMsg of string

我的问题是,mutable F#filename保持不变,尽管它是在C#函数中分配的(与out string相同而不是ref string同样存在)

2 个答案:

答案 0 :(得分:4)

在F#ref中不是关键字,而是创建引用单元格的函数。 Xlsx.TestSave(proposed, ref filename, ref save_log)因此将两个新创建的ref个单元格(指向mutable string值)传递到TestSave,这又将ref单元格更改为指向string 1}}已分配。不幸的是,这不是从外部观察到的,因为没有任何指向ref细胞的东西。一种方法是:

let getUserFile(proposed) : UserFile =
   let filename = ref ""
   let save_log = ref ""
   match Xlsx.TestSave(proposed, filename, save_log) with
   | true -> FileResult(!filename)
   | false -> ErrorMsg(!save_log)

如@kvb所述,您也可以使用

let getUserFile(proposed) : UserFile =
   let mutable filename = ""
   let mutable save_log = ""
   match Xlsx.TestSave(proposed, &filename, &save_log) with
   | true -> FileResult(filename)
   | false -> ErrorMsg(save_log)

并自F# 4.0 simplified the use of mutables vs. ref以来完全摆脱ref

此外,我尝试避免match简单bool,传统if then else更短:

let getUserFile(proposed) : UserFile =
   let mutable filename = ""
   let mutable save_log = ""
   if Xlsx.TestSave(proposed, &filename, &save_log) then
       FileResult(filename)
   else
       ErrorMsg(save_log)

显然,using out instead of ref甚至更好,但对于" ...已经存在的库..."你可能没有这个选择。

答案 1 :(得分:2)

如果您在C#端使用out而不是ref,那么您应该可以这样做:

let getUserFile(proposed) : UserFile =
    match Xlsx.TestSave proposed with
    | true, filename, _  -> FileResult(filename)
    | false, _, save_log -> ErrorMsg(save_log)

因为尾随out参数可以被视为具有实际结果类型的元组。