与ref传递的参数进行互操作

本文关键字:互操作 参数 ref | 更新日期: 2023-09-27 18:18:33

我正在尝试调用一个已经存在的库的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)

表示将函数转换为代数数据类型,目的是使非法状态不可表示。

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相同的问题)

与ref传递的参数进行互操作

在f#中ref不是一个关键字,而是一个创建参考单元格的函数。因此,Xlsx.TestSave(proposed, ref filename, ref save_log)将两个新创建的ref引用单元格(指向mutable string的值)传递给TestSave,进而将ref单元格更改为指向string分配的任何值。不幸的是,这是无法从外部观察到的,因为没有任何指向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)

和完全摆脱ref s,因为f# 4.0简化了mutable s与ref的使用。

此外,我尽量避免在简单的bool上使用match,传统的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)

显然,使用out代替ref更好,但是对于"…一个已经存在的库…"你可能没有这个选择

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

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

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