For any .NET type which cannot be represented in Excel via built-in or custom converter FCell will automatically create a handle.

Object handle is simply a string identifier for a live object instance e.g. MyTypeName@n, where n = 0,1,... is an automatically created unique index.

Note

Object handle is created automatically for any .NET type, including all .NET framework types, so access to the type source code is not required.

You can use existing instance constructors to create object handles. Instance constructors are automatically exposed as UDFs with Excel name MyClass.createMyClass.

Create object handle and pass it as UDF argument

As an example we will create UDFs which use a type from .NET framework: System.Collections.Generic.List<int>:

F# Copy imageCopy
namespace Test
module Udfs =
    open FCell.ManagedXll
    open System
    open System.Collections.Generic

    let createList n =
        let list = new List<_>()
        for i in 0..n-1 do
            list.Add(i)
        list

    let getItem (list : List<int>) i = list.[i]
C# Copy imageCopy
using FCell.ManagedXll;
using System;
using System.Collections.Generic;
namespace Test
{
    public class CSharpUdfs
    {
        public static List<int> CreateList(int n)
        {
            var list = new List<int>();
            for (int i = 0; i < n; i++)
            {
                list.Add(i);
            }
            return list;
        }

        public static int GetItem(List<int> list, int index)
        {
            return list[index];
        }
    }
}
Visual Basic Copy imageCopy
Imports System
Imports System.Collections.Generic
Imports FCell.ManagedXll

Namespace Test
    Public Class VBUdfs
        Public Shared Function CreateList(ByVal n As Integer) As List(Of Integer)
            Dim list = New List(Of Integer)()
            For i As Integer = 0 To n-1
                list.Add(i)
            Next
            Return list
        End Function

        Public Shared Function GetItem(ByVal list As List(Of Integer), ByVal index As Integer) As Integer
            Return list(index)
        End Function        
    End Class
 End Namespace

You can now use createList and it will return a string handle List<Int32>@n n=0,1...

Once you have a handle, you can pass it to GetItem function which expects an instance of List<int> as first argument.

Note

Object handles are RTD based. When you delete the handle in Excel, the corresponding object is released for garbage collection. If the object implements IDisposable, Dispose will also be called.

The RTD mechanism will also ensure that all object handles are recreated when you open the workbook.

Note

You can also return object handles from async and reactive UDFs.

F# function handle and partial application

F# functions are instances of FSharpFunc<T1, T2> and as such can be used in Excel as handles.

In addition, FCell has 4 built-in UDFs which allow you to partially apply up to 4 arguments: Func.Apply1Arg, Func.Apply2Args, Func.Apply3Args and Func.Apply4Args

Each of those functions expects a handle to F# function as its first argument, followed by 1, 2, 3 or 4 arguments that the F# function expects.

F# Copy imageCopy
namespace Test
module Udfs =

    let createFun() =
        () // will force compiler to emit FSharpFunc<T1,T2>
        fun x y -> x + y    
    let applyFun (f : int -> int -> int) x y = f x y //generic functions are not exposed as UDFs

You can now use createFun in Excel and it will return a handle to F# function FSharpFunc<Int32,FSharpFunc<Int32,Int32>>@n

Once you have a handle, you can pass it to one of the built-in functions, e.g. Func.Apply1Arg(handle,1) will return a new handle FSharpFunc<Int32,Int32>@n and Func.Apply2Args(handle, 2, 3) will apply the function fully and return 5.

You can also pass a handle to any higher order F# function, e.g. applyFun(handle, 2, 3) will return 5