Skip to content

[API Proposal]: UnsafeAccessorTypeAttribute for static or private type access #90081

@AaronRobinsonMSFT

Description

@AaronRobinsonMSFT

Background and motivation

The UnsafeAccessorAttribute mechanism was designed to provide access to a non-visible static or instance member (that is, method or field). There are however limitations with this design when involving static types or accessing members on non-visible types. This attribute helps bridge that gap.

Consider the following two scenarios involving methods. Note that fields suffer from the same issue.

Scenario 1 - Private type

// Assembly A
private class C
{
    private static int Method(int a) { ... }
}
// Assembly B
[UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name="Method")]
static extern int CallMethod(??? c, int a); // One cannot write type C due to visibility.

Scenario 2 - Static type

// Assembly A
public static class C
{
    private static int Method(int a) { ... }
}
// Assembly B
[UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name="Method")]
static extern int CallMethod(??? c, int a); // A static class cannot be used as a parameter in a signature.

Scenario 3 - Private class parameters

// Assembly A
public class C
{
    private class D { }
    private static int Method(D d) { ... }
}
// Assembly B
[UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name="Method")]
static extern int CallMethod(??? d); // Unable express D type as a parameter.

API Proposal

The following attribute would accept a fully qualified or partially qualified type name to use for member look-up. The string supplied via the typeName would be in a format that is accepted by Type.GetType(string typeName). This API will be specifcally limited by what that API is capable of. There may be additional restrictions for the initial implementation of this. For example, it only works on reference types for now.

namespace System.Runtime.CompilerServices;

[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.ReturnValue, AllowMultiple = false, Inherited = false)]
public sealed class UnsafeAccessorTypeAttribute : Attribute
{
    /// <summary>
    /// Instantiates an <see cref="UnsafeAccessorTypeAttribute"/> providing access to a type supplied by <paramref name="typeName"/>.
    /// </summary>
    /// <param name="typeName">A fully qualified or partially qualified type name.</param>
    public UnsafeAccessorTypeAttribute(string typeName)
    {
        TypeName = typeName;
    }

    /// <summary>
    /// Fully qualified or partially qualified type name to target.
    /// </summary>
    public string TypeName { get; }
}

API Usage

Scenario 1 - Private type

// Assembly A
private class C
{
    private static int Method(int a) { ... }
}
// Assembly B
[UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name="Method")]
static extern int CallMethod([UnsafeAccessorType("C, A, Version=1.0.0.0, Culture=neutral")] object c, int a);

Scenario 2 - Static type

// Assembly A
public static class C
{
    private static int Method(int a) { ... }
}
// Assembly B
[UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name="Method")]
static extern int CallMethod([UnsafeAccessorType("C, A")] object? c, int a);

Scenario 3 - Private class parameters

// Assembly A
public class C
{
    private class D { }
    private static int Method(D d) { ... }
}
// Assembly B
[UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name="Method")]
static extern int CallMethod([UnsafeAccessorType("C, A")] object? c, [UnsafeAccessorType("C+D, A")] object d); // Use attribute to look up type

Alternative Designs

Expand the UnsafeAccessorAttribute attribute to have an optional type target field/property. Note This API option wouldn't address scenario (3).

namespace System.Runtime.CompilerServices;

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public sealed class UnsafeAccessorAttribute : Attribute
{
+    /// <summary>
+    /// Fully qualified or partially qualified type name to target.
+    /// </summary>
+    public string TargetTypeName { get; set; }
}

Risks

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    api-approvedAPI was approved in API review, it can be implementedarea-System.Runtime.CompilerServicesin-prThere is an active PR which will close this issue when it is merged

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions