Skip to content

F# Guide — .NET Interop: Calling C# Code from F#

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about F# Guide. We cover key concepts, practical examples, and best practices to help you master this topic.

F# interoperates with C# and the .NET ecosystem by directly calling .NET APIs, creating objects, implementing interfaces, and consuming C# libraries with minimal friction.

What You'll Learn

  • Calling .NET methods from F#
  • Creating and using .NET objects
  • Implementing C# interfaces
  • Handling null values
  • Exposing F# code to C#

Why It Matters

The entire .NET ecosystem is available from F#. You can use any C# library, framework, or tool while writing F# code.

Real-World Use

Using ASP.NET Core, Entity Framework, Azure SDKs, and NuGet packages from F# applications.

flowchart LR
    A[".NET Interop"] --> B["Calling .NET APIs"]
    B --> C["Creating Objects"]
    C --> D["Interfaces"]
    D --> E["C# Consumers"]
    A:::current --> B
    style A fill:#2563eb,stroke:#2563eb,color:#fff
    style B fill:#dbeafe,stroke:#2563eb,color:#1e40af
    style C fill:#dbeafe,stroke:#2563eb,color:#1e40af
    style D fill:#dbeafe,stroke:#2563eb,color:#1e40af
    style E fill:#f1f5f9,stroke:#94a3b8,color:#64748b

Calling .NET Methods

open System

// Static methods
let now = DateTime.Now
let parsed = DateTime.Parse("2024-01-15")
let guid = Guid.NewGuid()

// Instance methods
let s = "hello world"
let upper = s.ToUpper()
let replaced = s.Replace("hello", "hi")

Creating .NET Objects

open System.Collections.Generic

// Constructor
let list = List<int>()  // C# List<int>
list.Add(1)
list.Add(2)

// With parameters
let dict = Dictionary<string, int>()
dict.["key"] = 42

// StringBuilder
let sb = System.Text.StringBuilder()
sb.Append("Hello")
sb.Append(" World")
let result = sb.ToString()

Properties and Events

open System.Net

// Properties
let client = new WebClient()
client.Headers.Add("User-Agent", "F#")
let data = client.DownloadString("http://example.com")

// Events
let timer = new System.Timers.Timer(1000.0)
timer.Elapsed.Add(fun args ->
    printfn "Tick at %A" args.SignalTime)
timer.Start()

Implementing Interfaces

type IComparer<'T> =
    abstract Compare: 'T * 'T -> int

// Object expression implementation
let reverseComparer =
    { new IComparer<int> with
        member _.Compare(x, y) = compare y x }

// Full class implementation
type MyComparer() =
    interface IComparer<int> with
        member _.Compare(x, y) = compare y x

Handling Null

// Nullable values
let nullableInt: System.Nullable<int> = System.Nullable(42)
let hasValue = nullableInt.HasValue
let value = nullableInt.Value

// Option to Nullable
let toNullable opt =
    match opt with
    | Some x -> System.Nullable(x)
    | None -> System.Nullable()

// Null checks
let getStringLength (s: string) =
    if isNull s then 0
    else s.Length

Exposing F# to C#

// F# class visible to C#
type FSharpCalculator() =
    member _.Add(x: int, y: int) = x + y
    member _.Subtract(x: int, y: int) = x - y

// F# record visible to C#
[<CLIMutable>]
type Person = {
    Name: string
    Age: int
}

// F# module with static members
[<AbstractClass; Sealed>]
type FSharpUtils =
    static member Square x = x * x

Using NuGet Packages

// Add package: dotnet add package Newtonsoft.Json
open Newtonsoft.Json

type User = { Name: string; Email: string }

let user = { Name = "Alice"; Email = "a@example.com" }
let json = JsonConvert.SerializeObject(user)
let deserialized = JsonConvert.DeserializeObject<User>(json)

Common Mistakes

1. NullReferenceException

C# code may return null. Check with isNull or use Option.ofObj.

2. Mutable state surprises

C# objects are mutable. Assign to immutable bindings carefully.

3. Value type boxing

Be aware of boxing when passing F# values to APIs expecting object.

4. Event subscription leaks

Unsubscribe from events when done to prevent memory leaks.

5. Exception Handling

C# methods throw exceptions. Use try-with to handle expected exceptions.

Practice Questions

1. How do you call a .NET static method from F#? Use ClassName.MethodName(args). For example: DateTime.Now.

2. How do you create a .NET object? Use the constructor: ClassName(args) or new ClassName(args).

3. How do you implement an interface in F#? Use object expressions: { new IInterface with member ... }.

Challenge: Create an F# class that implements IEnumerable and can be used from C#.

FAQ

{{< faq question="Can I use all NuGet packages with F#?" >} Yes. Any NuGet package targeting .NET Standard or .NET works with F#. {{< /faq >}}

{{< faq question="How do I handle IDisposable in F#?" >} Use the use keyword: use reader = new StreamReader(path). {{< /faq >}}

{{< faq question="Can F# code be used from C#?" >} Yes. F# classes, records (with CLIMutable), and modules compile to standard .NET types visible from C#. {{< /faq >}}

{{< faq question="How do I access indexers?" >} Use .[index] syntax for .NET indexers. Example: list.[0]. {{< /faq >}}

{{< faq question="What is object expression?" >} A syntax to create an ad-hoc implementation of an interface without defining a named class. {{< /faq >}}

Mini Project

Create an F# wrapper around a C# library:

open System.Net.Http
open System.Text.Json

type ApiClient(baseUrl: string) =
    let client = new HttpClient()
    do client.BaseAddress <- System.Uri(baseUrl)

    member this.GetUserAsync userId = task {
        let! response = client.GetAsync($"/users/{userId}")
        response.EnsureSuccessStatusCode() |> ignore
        let! json = response.Content.ReadAsStringAsync()
        return JsonSerializer.Deserialize(json)
    }

    member this.CreateUserAsync name email = task {
        let body = JsonSerializer.Serialize({| Name = name; Email = email |})
        let content = new StringContent(body, System.Text.Encoding.UTF8, "application/json")
        let! response = client.PostAsync("/users", content)
        return response.IsSuccessStatusCode
    }

    interface System.IDisposable with
        member this.Dispose() = client.Dispose()

What's Next

Now that you understand .NET interop, explore Fable for compiling F# to JavaScript.

Topic Description Link
F# Fable F# to JavaScript {{< ref "28-fable" >}}
F# Paket Package management {{< ref "29-paket" >}}

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro