techmore.in

C# - Function Pointers

In C#, function pointers are a feature introduced in C# 9.0, which allow you to work with unmanaged function pointers (similar to pointers in languages like C or C++). They enable direct invocation of methods through memory addresses, providing more control and efficiency, particularly useful in scenarios where you need low-level memory manipulation, performance optimizations, or interoperability with unmanaged code.

Key Features of Function Pointers:

  1. Unmanaged Context: Function pointers must be used in an unsafe context because they deal directly with memory, which bypasses some safety checks in managed code.
  2. High Performance: Function pointers allow for fast invocation of functions, avoiding the overhead of delegate invocation or virtual method calls.
  3. Interoperability: Useful when interacting with native libraries, such as through P/Invoke or calling unmanaged C/C++ functions.

Declaring a Function Pointer:

To declare and use a function pointer, you need to use the delegate* keyword in an unsafe block.

Syntax:

csharp
unsafe delegate*<ParameterTypes, ReturnType> functionPointer;
  • delegate* declares the function pointer.
  • <ParameterTypes, ReturnType> specifies the types of parameters the function takes and the return type.

Example of Function Pointer Declaration:

csharp
unsafe { // Declare a function pointer that takes two integers and returns an integer delegate*<int, int, int> addPointer; // Assign the address of a function to the function pointer addPointer = &Add; // Use the function pointer to call the method int result = addPointer(10, 20); Console.WriteLine(result); // Output: 30 } // Regular method to be used with a function pointer static int Add(int a, int b) { return a + b; }

Calling Convention:

You can also specify a calling convention when working with unmanaged function pointers. This tells the runtime how the arguments should be passed to the function and how the return value should be handled.

csharp
unsafe delegate* unmanaged[Cdecl]<int, int, int> addPointer;
  • unmanaged[Cdecl] specifies the calling convention (in this case, Cdecl, commonly used in C/C++).
  • Other calling conventions include Stdcall, Thiscall, and Fastcall.

Example with Interop (Calling a Native Function):

csharp
[DllImport("SomeNativeLibrary.dll", CallingConvention = CallingConvention.Cdecl)] public static extern unsafe delegate*<int, int, int> GetAddFunctionPointer(); unsafe { // Retrieve the function pointer from a native library delegate*<int, int, int> addPointer = GetAddFunctionPointer(); // Use the function pointer to call the native function int result = addPointer(10, 20); Console.WriteLine(result); // Calls the native add function }

Key Points:

  • Unsafe Context: Function pointers require the unsafe keyword because they bypass many of C#'s managed runtime features (like garbage collection safety).
  • No Garbage Collection: Function pointers are unmanaged, meaning they are not tracked by the garbage collector, so you need to manage memory carefully.
  • Performance: They offer a more performant alternative to delegates or virtual method calls in certain scenarios.
  • Interoperability: Function pointers are ideal for use cases where you need to interact with unmanaged code, such as calling functions from native libraries.