- 
                Notifications
    You must be signed in to change notification settings 
- Fork 5.2k
Description
Background and motivation
This is the proposed API to support introspection of Function Pointers (delegate*) based on the user story, original issue and function pointer design. In summary, when function pointers were added in 5.0 the corresponding support for reflection was not added which resulted in an IntPtr being returned as the type when using typeof or reflection. This feature changes that to now return System.Type which then allows access to function pointer metadata including the calling convention, return type and parameters. This is a breaking change.
UPDATE: the original approved API for .NET 7 was not implemented due to concerns with breaking scenarios with managed C++ and adding unnecessary runtime overhead. This .NET 8 proposal changes the design to return "modified types" that expose custom modifiers on function pointers instead of exposing them on runtime-based types.
Corresponding support will also be added to MetadataLoadContext. The inbox version will have full support but the netstandard version, for simplicity, will  throw NotSupportedException for the new members that return new types (since they are not in netstandard). For members that don't return new types, it will be possible to use reflection to invoke them.
This API issue is focused on introspection; the links above have additional features that can be layered on this including support for IL Emit.
API Proposal
namespace System
{
    public abstract class Type
    {
+       public virtual bool IsFunctionPointer { get; }
+       public virtual bool IsUnmanagedFunctionPointer { get; }
        // These throw InvalidOperationException if IsFunctionPointer = false:
+       public virtual Type GetFunctionPointerReturnType();
+       public virtual Type[] GetFunctionPointerParameterTypes();
        // These require a "modified type" to return custom modifier types:
+       public virtual Type[] GetRequiredCustomModifiers();
+       public virtual Type[] GetOptionalCustomModifiers();
+       public virtual Type[] GetFunctionPointerCallingConventions(); // Throws if IsFunctionPointer = false
    }
}
// Return a "modified type" from a field, property or parameter if its type is a:
// - Function pointer type
// - Pointer or array since they may reference a function pointer
// - Parameter or return type from a function pointer
namespace System.Reflection
{
    public abstract class FieldInfo
    {
+       public virtual Type GetModifiedFieldType() => throw new NotSupportedException();
    }
    public abstract class PropertyInfo
    {
+       public virtual Type GetModifiedPropertyType() => throw new NotSupportedException();
    }
    public abstract class ParameterInfo
    {
+       public virtual Type GetModifiedParameterType() => throw new NotSupportedException();
    }
}A modified type's UnderlyingSystemType property returns the unmodified type and all members on a modified forward to that except:
- GetRequiredCustomModifiers()
- GetOptionalCustomModifiers()
- GetFunctionPointerCallingConventions()
- GetFunctionPointerParameterTypes()
- GetFunctionPointerReturnType()
which instead return the information kept on the modified type.
API Usage
See the design referenced above. Here's some short examples:
Type type = typeof(delegate*<int, bool>);
bool b = type.IsFunctionPointer(); // true
string s = type.ToString(); // "System.Boolean(System.Int32)"
Type returnType = type.GetFunctionPointerReturnType(); // System.Boolean
Type param1Type = type.GetFunctionPointerParameterTypes()[0]; // System.Int32
FieldInfo fieldInfo = typeof(Util).GetField("_field")!;
bool isUnmanaged = fieldInfo.FieldType.IsUnmanagedFunctionPointer; // true
// Get the modified type in order to obtain the custom modifiers
Type modifiedType = fieldInfo.GetModifiedFieldType();
// Get the unmanaged calling conventions
type = modifiedType.GetFunctionPointerCallingConventions()[0]; // CallConvCdecl
// Get the first custom modifier from the first parameter
type = modifiedType.GetFunctionPointerParameterTypes()[0].GetRequiredCustomModifiers()[0]; // OutAttribute
unsafe public class Util
{
    public delegate* unmanaged[CDecl]<out bool, void>; _field;
}Risks
The breaking change nature of not returning IntPtr any longer.