F# compiles to ordinary .NET assemblies, so every .NET library can be used from F# and every F# library can be used from other .NET languages, with a few places where the two models differ.
Using .NET from F#
open System
open System.Collections.Generic
open System.IO
let list = List<string>() // a .NET generic class
list.Add "a"
let ok, value = Int32.TryParse "42" // out parameters come back as a tuple
let text = File.ReadAllText(@"C:\data.txt") // a static method
let dt = DateTime(2026, 11, 14) // a constructor, without new
let now = DateTime.Now.AddDays(1.0).ToString("O")
let button = new System.Windows.Forms.Button() // an event:
button.Click.Add(fun _ -> printfn "clicked")
let handler = EventHandler(fun s e -> ()) // a delegate from a lambda
let f = Func<int, int>(fun x -> x + 1) // F# function to Func
let xs = [| 3; 1; 2 |] |> Array.sort
let q = System.Linq.Enumerable.Where(xs, fun x -> x > 1)
- Methods take their arguments in brackets, separated by commas, as one tuple; a call with one argument may omit the brackets (
list.Add "a"). Named arguments (Foo(name = "x")) and property setters in a constructor call (Button(Text = "OK")) are allowed. Overloads are resolved by the argument types. outandrefparameters may be omitted and returned in a tuple; or passed as&xof a mutable value.- A lambda is converted to a delegate or a
Func/Actionwhere a method wants one; elsewhere write the delegate type. F# 11 keeps a delegate’s own metadata when one is made directly. - Methods with
paramsarrays take any number of arguments;[<Optional>]parameters may be left out. - C# extension methods are used with the dot after the namespace is opened. F# 6 uses
op_Implicitconversions where an argument needs them (with optional warnings 3391 and 3395). - Events are values with
.Add,.AddHandlerand.RemoveHandler, and can be used asIObservablewith theObservableandEventmodules. - Properties and fields are read as
x.Name, written withx.Name <- v. Indexers arex.[i]orx[i].
Null
A .NET reference value may be null; F# types do not accept it (see types). isNull x tests, null is the value, Option.ofObj and Option.toObj convert to and from option, and [<AllowNullLiteral>] lets an F# class be null. From F# 9, with nullness checking on, string | null is the type of a possibly-null string and the compiler checks use against C# nullable annotations; F# 11 understands the NotNullIfNotNull promise.
Byrefs, spans and pointers
let readIt (dt: inref<DateTime>) = dt.Year
let incr (x: byref<int>) = x <- x + 1
let mutable n = 0
incr &n // pass the address of a mutable
let d = DateTime.Now
readIt &d
[<Struct; IsByRefLike>]
type Window(span: System.Span<byte>) =
member _.Length = span.Length
let bytes = [| 1uy; 2uy |]
let s = Span<byte>(bytes)
open Microsoft.FSharp.NativeInterop
let p = &&n // a native pointer from a mutable local
let v = NativePtr.read (NativePtr.ofNativeInt<int> 0n)
Span and native pointers.byref<'T> is a managed pointer for reading and writing, inref<'T> for reading and outref<'T> for writing; a byref can be passed where an inref or outref is expected. To pass a value by reference take its address with &; to write through it, the value must be mutable. A byref-like struct ([<IsByRefLike>]) has the same limits as a byref: it cannot be captured by a closure or stored in a field of an ordinary type. fixed pins an array or string and gives a nativeptr; NativePtr operations (ofNativeInt, toNativeInt, read, write, get, set, add, toByRef, stackalloc and, since F# 6, nullPtr, isNullPtr, initBlock, clear, copy, copyBlock, ofILSigPtr, toILSigPtr) work on them, and F# 4.5 added NativePtr.ofVoidPtr and toVoidPtr.
Native code
open System.Runtime.InteropServices
[<Literal>]
let LibName = "native"
[<DllImport(LibName, CallingConvention = CallingConvention.Cdecl)>]
extern int add_numbers(int a, int b)
[<DllImport("user32.dll", CharSet = CharSet.Unicode)>]
extern int MessageBox(nativeint hWnd, string text, string caption, uint32 options)
let sum = add_numbers(1, 2)
extern in C-like syntax and the DllImport attribute.The first argument of DllImport is the library name; because attribute arguments must be known at compile time, a name held in a value has to be a [<Literal>]. The declaration uses C type syntax with F# type names. This is platform invoke, a feature of the runtime.
Using F# from other .NET languages
- A module is a static class; a function is a static method. A curried function
let f a bbecomes a method with two parameters; a function with a function-typed parameter takesFSharpFunc<…>(convert withFuncConvertor acceptFunc<…>in a member). Members of a class are methods, so they take tupled arguments and look normal to C#. - A record is an immutable class (add
[<CLIMutable>]for a parameterless constructor and setters); a union is a class hierarchy with one nested class for each case andIs*properties (visible to C# from F# 9);optionandlistare the FSharp.Core typesFSharpOption<T>andFSharpList<T>. [<CompiledName("Name")>]sets the .NET name;[<Extension>]on a static member in a class with the same attribute makes a C# extension method;[<CLIEvent>]publishes a .NET event;asyncis converted withAsync.StartAsTaskand ataskis already aTask.- The project references the
FSharp.Corepackage; the page on FSharp.Core targets in the documentation lists the target frameworks (netstandard2.0andnetstandard2.1builds, and a build for modern .NET) and the differences between them.
Not described
Known, not yet covered
- Reference: overload resolution rules, the rules of implicit conversions, optional-argument encodings, interface implementation across languages, COM interop, the details of
NativePtrandfixed(the F# 8 extended bindings), the target-framework differences of FSharp.Core and the runtime-async mode are only named. - Reference: of the documentation pages for these topics only the external functions and byref pages were read, in part; the example code was written for this page and not compiled, and the names of the NativePtr functions come from the F# 6 release page and the library interface.
See also
- Classes and objects – defining .NET-style types
- The standard library – the F# core library