A function pointer in C# is a lightweight, strongly-typed, unmanaged pointer to a memory address containing executable code. Introduced in C# 9.0, function pointers provide a mechanism to invoke methods directly via the Intermediate Language (IL)Documentation Index
Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt
Use this file to discover all available pages before exploring further.
calli instruction, bypassing the heap allocation, object instantiation, and virtual dispatch overhead associated with traditional System.Delegate types.
Because they deal directly with memory addresses, function pointers can only be declared and used within an unsafe context.
Syntax and Declaration
Function pointers are declared using thedelegate* keyword, followed by type parameters enclosed in angle brackets. The type parameters specify the method signature, where the final type parameter always represents the return type.
Assignment and Invocation
To assign a method to a function pointer, you use the address-of operator (&) followed by the method name. Function pointers can point to both static and instance methods.
While function pointers do not capture state (closures) or maintain an object reference like delegates, an instance method can be targeted by including the instance’s type as the first parameter in the function pointer’s signature. This explicitly represents the hidden this pointer required by instance methods.
Managed vs. Unmanaged Function Pointers
Function pointers are categorized by their calling convention, which dictates how arguments are passed to the function and how the stack is cleaned up. 1. Managed Function Pointers By default, adelegate* uses the standard .NET managed calling convention. It can only point to managed C# methods.
2. Unmanaged Function Pointers
To point to unmanaged code (e.g., native C/C++ libraries), you must specify the unmanaged keyword. You can optionally define the specific unmanaged calling convention using a bracketed syntax. If the brackets are omitted, the runtime uses the default platform calling convention.
Mutually exclusive calling conventions (like Cdecl and Stdcall) cannot be combined. Multiple types within the bracket syntax are strictly reserved for combining a single calling convention with specific compiler modifiers.
When using the bracket syntax, the C# compiler automatically prepends the CallConv prefix to the identifiers you specify. Therefore, while the underlying type in the System.Runtime.CompilerServices namespace might be named CallConvSuppressGCTransition, the CallConv prefix must be strictly omitted in the C# language syntax to avoid compiler errors (e.g., CS8892).
Architectural Differences from Delegates
To understand function pointers technically, it is necessary to contrast them withSystem.Delegate:
- Memory Allocation: A
Delegateis a reference type that requires heap allocation. Adelegate*is a raw memory address (an unmanaged pointer type), requiring zero heap allocation. - Invocation Mechanism: Invoking a
Delegaterequires a virtual method call (callvirt) to the delegate’sInvokemethod, which then resolves the target. Invoking adelegate*emits thecalli(Call Indirect) IL instruction, jumping directly to the memory address. - State: A
Delegatemaintains an invocation list and an object reference (Target) for instance methods. Adelegate*holds no state, no closure, and no object reference. - Type System:
delegate*types are not derived fromSystem.Object. They cannot be boxed, cannot be used as generic type arguments (e.g.,List<delegate*<void>>is invalid), and cannot be used in reflection without specialized metadata handling.
Master C# with Deep Grasping Methodology!Learn More





