TimothyP
TimothyP

Reputation: 21765

Passing an object from F# into a C# method which takes it as an out parameter doesn't work?

One of the libraries I'm using defines this in C#:

public ushort GetParameterSet(string name, out ParameterSet parameterSet)

I'm trying to call this from F#:

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

However, even though the parameterSet is set to an instance of that class with valid data in the C# method, it does not change in F#.

What am I missing here?

Upvotes: 3

Views: 1760

Answers (2)

Tamás Szelei
Tamás Szelei

Reputation: 23971

Try

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

You shouldn't pass an instance as ref parameter, when the method expects an out parameter (which upon calling should be an unassigned reference preceded by the out keyword).

Upvotes: 4

Pavel Minaev
Pavel Minaev

Reputation: 101665

First of all, why your code doesn't work as is: ref doesn't have the same meaning in F# as it does in C#. In F#, 'a ref is a type. It's not magical, either - it's really just a record with a single field contents, defined as follows:

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

It is not a pointer or reference to a local variable. Thus, when you write this:

let x = 0
let y = ref x

you do not have variable y referencing x. Instead, you have variable y of type int ref, with the value of contents initialized to the value that x had (that is 0). You can change that:

y.contents <- 1

and this will not change the value of x. It will only change the value of contents

F# also provides some syntactic sugar for 'a ref. Specifically, this:

y.contents <- y.contents + 1

can be written shorter as:

y := !y + 1

Thus := is a shorthand for assigning to contents, and ! is a shorthand for reading its value.

See Reference Cells in MSDN for more information on ref.

Now F# has a magic cast associated with 'a ref type, that lets you pass an instance of that type to a foreign function that expects a byref argument (both ref and out in C# map to byref in IL). In this case, if function changes the value of the argument, the value of contents in your ref instance changes accordingly. In your example, ref parameterSet created a new instance of ref, passed it to function which changed it, and then discarded it. What you should have done is this:

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

Alternatively, you could use let mutable to declare a mutable local variable, and then use the magical & operator to pass it to the function directly as byref:

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

Upvotes: 12

Related Questions