Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[API Proposal]: Diagnostic method information #96528

@MichalStrehovsky

Description

@MichalStrehovsky

Background and motivation

There are diagnostic scenarios for which people currently use reflection:

  • Obtaining information about a method on a stack frame (StackFrame.GetMethod)
  • Obtaining information about a target of a delegate (Delegate.Method)

These APIs return a fully functional MethodBase instance.

This poses a problem for trimming because the MethodBase returned from these APIs needs to be fully functional (up to and including providing the ability to invoke the method). This means the MethodBase needs to have intact parameter names, custom attributes including all the nullable annotation cruft, etc.

Trimming currently approaches this two ways:

  1. StackFrame.GetMethod is marked as RequiresUnreferencedCode. Accessing it in a trimmed or AOT'd app produces a build time warning. The property may or may not return a null or an incomplete/damaged MethodInfo. It will mostly return a damaged/incomplete MethodInfo in a trimmed app (e.g. missing parameter names), and mostly return null in an AOT'd app.
  2. Delegate.Method is trim safe. Trimming and AOT ensure all delegate targets are considered reflection visible.

Solution 1 currently blocks some customer scenarios (#92869) that people are not able to do well in trimmed apps.
Solution 2 leaves size savings on the table.

Fundamentally, many of the use cases of StackFrame.GetMethod/Delegate.Method only need names of things, they don't actually need the whole MethodBase. For example, the use cases in #92869, or our own use cases within the framework like

TplEventSource.Log.TraceOperationBegin(this.Id, "Task: " + m_action.Method.Name, 0);

The proposal is to introduce a new API that would be trim safe and produce just the name part, using a more limited portion of the metadata.

API Proposal

namespace System.Diagnostics;

public sealed class DiagnosticMethodInfo
{
    // Returns name of the method, same as MethodInfo.Name
    public string Name { get; }

    // Returns FullName of the declaring type. Same as MethodInfo.DeclaringType.FullName
    public string DeclaringTypeName { get; }

    // Returns full name of the declaring assembly, same as MethodInfo.Module.Assembly.FullName
    public string DeclaringAssemblyName { get; }
}

public static void DiagnosticExtensions
{
    // These return a nullable result because if the app is aggressively trimmed (e.g. `StackTraceSupport` https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/trimming-options?pivots=dotnet-6-0#trimming-framework-library-features feature switch is disabled), we might return null
    public static DiagnosticMethodInfo? GetDiagnosticMethodInfo(this Delegate del);
    public static DiagnosticMethodInfo? GetDiagnosticMethodInfo(this StackFrame frame);
}

API Usage

Action a = Method;

Console.WriteLine($"Delegate points to {a.GetDiagnosticMethodInfo()?.Name ?? "Unknown method"});

Alternative Designs

Don't trim any metadata from methods that are statically reachable so that StackFrame.Method always works. This is an instant 20% size regression for AOT (where we don't just trim names of parameters, but also other things), probably a little less for IL level trimming (where we currently only trim parameter names).

Risks

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    api-approvedAPI was approved in API review, it can be implementedarea-System.DiagnosticsenhancementProduct code improvement that does NOT require public API changes/additions

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions