【问题标题】:Passing an object from F# into a C# method which takes it as an out parameter doesn't work?将对象从 F# 传递到将其作为输出参数的 C# 方法不起作用?
【发布时间】:2009-08-13 18:55:19
【问题描述】:

我使用的一个库在 C# 中定义了这个:

public ushort GetParameterSet(string name, out ParameterSet parameterSet)

我正在尝试从 F# 调用它:

let parameterSet = new ParameterSet();
let retVal = currentPanel.GetParameterSet(name, ref parameterSet);

然而,即使 parameterSet 被设置为那个的实例 在 C# 方法中具有有效数据的类,在 F# 中不会更改。

我在这里错过了什么?

【问题讨论】:

    标签: c# f# pass-by-reference


    【解决方案1】:

    首先,为什么您的代码不能按原样运行:ref 在 F# 中的含义与在 C# 中的含义不同。在 F# 中,'a ref 是一个类型。它也不是什么神奇的东西——它实际上只是一个包含单个字段contents 的记录,定义如下:

    type 'a ref = { mutable contents : 'a }
    

    不是指向局部变量的指针或引用。因此,当你写这个时:

    let x = 0
    let y = ref x
    

    没有变量y引用x。相反,您有int ref 类型的变量ycontents 的值初始化为x 的值(即0)。你可以改变它:

    y.contents <- 1
    

    这不会改变x 的值。它只会改变contents的值

    F# 还为'a ref 提供了一些语法糖。具体来说:

    y.contents <- y.contents + 1
    

    可以写成:

    y := !y + 1
    

    因此:= 是赋值给contents 的简写,! 是读取其值的简写。

    有关 ref 的更多信息,请参阅 MSDN 中的 Reference Cells

    现在 F# 有一个与 'a ref 类型关联的魔术转换,它允许您将该类型的实例传递给一个外部函数,该函数需要一个 byref 参数(C# 中的 refout 都映射到 @ 987654347@ 在伊利诺伊州)。在这种情况下,如果函数改变了参数的值,contents 在你的ref 实例中的值也会相应地改变。在您的示例中,ref parameterSet 创建了一个 ref 的新实例,将其传递给更改它的函数,然后将其丢弃。你应该做的是:

    let parameterSet = ref(new ParameterSet())
    let retVal = currentPanel.GetParameterSet(name, parameterSet)
    ...
    // use parameterSet.contents as needed
    

    或者,您可以使用let mutable 声明一个可变局部变量,然后使用神奇的&amp; 运算符将其作为byref 直接传递给函数:

    let mutable parameterSet = new ParameterSet()
    let retVal = currentPanel.GetParameterSet(name, &parameterSet)
    

    【讨论】:

      【解决方案2】:

      试试

      // let parameterSet = null;
      let retval, parameterSet = currentPanel.GetParamterSet(name);
      

      当方法需要一个 out 参数时,您不应将实例作为 ref 参数传递(调用时它应该是一个未分配的引用,前面有 out 关键字)。

      【讨论】:

      • 哇好...那么为什么 fsharp 有 ref 关键字,如果它不能那样工作,就允许它(顺便说一句,你的)
      • refout 之间的区别纯粹是 C# 的区别,在“外部”不可见 - 例如,VB 没有它,并将同时处理 C# refoutByRef。将初始化变量传递给out-参数当然没问题 - 即使在 C# 中,变量 必须 没有被赋值。
      • 我知道你可以,我的意思是你不应该。但我不知道这是仅限 C#,我认为这是 CLR 的事情。感谢您的澄清!
      • 为什么不呢?我可以有一个我已经使用过的值的变量,我只想用一个新的值覆盖它。将分配的变量传递给out-参数与使用operator= 为同一变量分配新值没有任何不同。两者都是完全合法的,并且有正当理由。也许您将此与传递给ref的变量必须初始化的要求混淆了,而out没有这样的限制?
      • 需要注意的是,F# 现在支持out 参数。虽然魔法脱糖仍然是最简单的。
      猜你喜欢
      • 1970-01-01
      • 2015-06-23
      • 2018-04-13
      • 2020-06-05
      • 1970-01-01
      • 1970-01-01
      • 2018-09-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多