Skip to content
This repository was archived by the owner on Sep 25, 2026. It is now read-only.
This repository was archived by the owner on Sep 25, 2026. It is now read-only.

DynamicallyAccessedMembers should transitively apply to GetInterfaces() #1731

Description

@eerhardt

If an interface Type is annotated with [DynamicallyAccessedMembers(All)], then any Types returned from interfaceType.GetInterfaces() should also assume to be annotated with the same member types.

Repro

Trimming the following application:

using System;
using System.Diagnostics.CodeAnalysis;

namespace ConsoleApp2
{
    interface IMyInterface : IFormattable
    {
        void M1();
    }

    class Program
    {
        static void Main(string[] args)
        {
            GenerateProxyType(typeof(IMyInterface));
        }

        private static void GenerateProxyType(
            [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type interfaceType)
        {
            foreach (Type t in interfaceType.GetInterfaces())
                AddInterfaceImpl(t);  // <--- Warning happens here

            AddInterfaceImpl(interfaceType);
        }

        static void AddInterfaceImpl([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type iface)
        {
        }
    }
}

Produces this warning:

Program.cs(22,17): Trim analysis warning IL2062: ConsoleApp2.Program.GenerateProxyType(Type): Value passed to parameter 'iface' of method 'ConsoleApp2.Program.AddInterfaceImpl(Type)' can not be statically determined and may not meet 'DynamicallyAccessedMembersAttribute' requirements.

Note, for some reason, when the ILLinker runs as part of the shared framework build, I am getting a different warning, I'm not sure if I'm using a different version of the ILLinker or not, but here is the code in DispatchProxy:

        internal void AddInterfaceImpl([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type iface)
        {
            ...
        }

        private static Type GenerateProxyType(
            [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type baseType,
            [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type interfaceType)
        {
            // Parameter validation is deferred until the point we need to create the proxy.
            // This prevents unnecessary overhead revalidating cached proxy types.

            // The interface type must be an interface, not a class
            if (!interfaceType.IsInterface)
            {
                // "T" is the generic parameter seen via the public contract
                throw new ArgumentException(SR.Format(SR.InterfaceType_Must_Be_Interface, interfaceType.FullName), "T");
            }

            // The base type cannot be sealed because the proxy needs to subclass it.
            if (baseType.IsSealed)
            {
                // "TProxy" is the generic parameter seen via the public contract
                throw new ArgumentException(SR.Format(SR.BaseType_Cannot_Be_Sealed, baseType.FullName), "TProxy");
            }

            // The base type cannot be abstract
            if (baseType.IsAbstract)
            {
                throw new ArgumentException(SR.Format(SR.BaseType_Cannot_Be_Abstract, baseType.FullName), "TProxy");
            }

            // The base type must have a public default ctor
            if (baseType.GetConstructor(Type.EmptyTypes) == null)
            {
                throw new ArgumentException(SR.Format(SR.BaseType_Must_Have_Default_Ctor, baseType.FullName), "TProxy");
            }

            // Create a type that derives from 'baseType' provided by caller
            ProxyBuilder pb = s_proxyAssembly.CreateProxy("generatedProxy", baseType);

            foreach (Type t in interfaceType.GetInterfaces())
                pb.AddInterfaceImpl(t);  // <--- Warning happens here

            pb.AddInterfaceImpl(interfaceType);

            Type generatedProxyType = pb.CreateType();
            return generatedProxyType;
        }

and the warning:

DispatchProxyGenerator.cs(139,17): Trim analysis warning IL2072: System.Reflection.DispatchProxyGenerator.GenerateProxyType(Type,Type): 'iface' argument does not satisfy 'All' in call to 'System.Reflection.DispatchProxyGenerator.ProxyBuilder.AddInterfaceImpl(Type)'. The return value of method 'System.Collections.Generic.IEnumerator<T>.Current.get' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to.

cc @vitek-karas @MichalStrehovsky

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions