简体   繁体   English

与ref传递的参数互操作

[英]Interop with parameters passed by ref

I'm trying to call a C# function of an already existing library (and I don't have time to port the whole library to F#) 我正在尝试调用现有库的C#函数(并且我没有时间将整个库移植到F#)

namespace ExportLib
{

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

from an F# code 从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)

meant to transform the function into algebraic data types with the objective to make illegal states unrepresentable . 意味着功能转化为代数数据类型,其目标是使非法状态不可表示

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

My issue is that the mutable F# filename remains unchanged despite it is assigned in the C# function (same problem with out string instead of ref string ) 我的问题是,尽管在C#函数中分配了mutable F# filenamefilename保持不变(用out string代替ref string同样的问题)

In F# ref is not a keyword but a function creating a reference cell. 在F#中, ref不是关键字,而是创建参考单元的函数。 Xlsx.TestSave(proposed, ref filename, ref save_log) thus passes two newly created ref erence cells (pointing to mutable string values) into TestSave which in turn changes the ref cell to point to whatever string is assigned. Xlsx.TestSave(proposed, ref filename, ref save_log)因此将两个新创建的ref单元格(指向mutable string值) TestSaveTestSave中,后者又将ref单元格更改为指向分配的任何string Unfortunately, this is not observable from the outside, as there's nothing pointing to the ref cells. 不幸的是,这是无法从外部观察到的,因为没有任何指向ref单元的内容。 One approach is: 一种方法是:

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)

As noted by @kvb you can also use 如@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)

and get rid of ref s altogether since F# 4.0 simplified the use of mutable s vs. ref . 并完全摆脱了ref因为F#4.0简化了mutable s与ref

Also, I try to avoid match ing on a simple bool , traditional if then else is shorter: 另外,我尽量避免match上简单的ING 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)

Obviously, using out instead of ref is even better, but for "... an already existing library ..." you might not have that choice. 显然, 使用out而不是ref甚至更好,但是对于“ ...一个已经存在的库...”,您可能没有这种选择。

If you use out instead of ref on the C# side, then you should be able to just do this instead: 如果您在C#端使用out而不是ref ,那么您应该能够做到这一点:

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

because trailing out parameters can be treated as a tuple with the actual result type. 因为后out参数可以被视为与实际结果类型的元组。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM