Skip to content

Attempts to create delegates from generic methods declared on interfaces throws NotSupportedException #100748

Open
@boxofyellow

Description

@boxofyellow

Description

If you have an interface declared as

public interface I1
{
    public void GenericFoo<T>();
}

And a delegate declared as

public delegate void InterfaceDelegate(I1 i1);

Attempting to create an instance of that delegate with this will throw a NotSupportedException

var genericMethod = typeof(I1).GetMethod(nameof(I1.GenericFoo))!;
var method = genericMethod.MakeGenericMethod(typeof(int));
//
// This is where the NotSupportedException is throne
//
method.CreateDelegate<InterfaceDelegate>(); 

However if you instead use a non-generic method (of corse MakeGenericMethod won't be needed) but it will be able to create an instance of the deligte. Additionally if you define a new a class with a generic method that has the same signature, and a delegate for that class's method you will be able to use similar code create an instance of that delegate.

Reproduction Steps

I tried this in dotnet 6.0.420 and 8.0.203

public interface I1
{
    public void GenericFoo<T>();
}

public delegate void InterfaceDelegate(I1 i1);

public class Program
{
    public static void Main()
    {
        var genericMethod = typeof(I1).GetMethod(nameof(I1.GenericFoo))!;
        var method = genericMethod.MakeGenericMethod(typeof(int));
        //
        // This is where the NotSupportedException is throne
        //
        method.CreateDelegate<InterfaceDelegate>(); 
    }
}

Expected behavior

The above program can be run without an exception.

Actual behavior

~/Repos/MinRepro > dotnet run
Unhandled exception. System.NotSupportedException: Specified method is not supported.
   at System.Delegate.BindToMethodInfo(Object target, IRuntimeMethodInfo method, RuntimeType methodType, DelegateBindingFlags flags)
   at System.Delegate.CreateDelegateInternal(RuntimeType rtType, RuntimeMethodInfo rtMethod, Object firstArgument, DelegateBindingFlags flags)
   at System.Reflection.RuntimeMethodInfo.CreateDelegateInternal(Type delegateType, Object firstArgument, DelegateBindingFlags bindingFlags)
   at System.Reflection.MethodInfo.CreateDelegate[T]()
   at Program.Main()
~/Repos/MinRepro >

Regression?

I have only tried 6.0 and 8.0 and the behavior seems to be the same in both.

Known Workarounds

One workaround I have found is to use a DynamicMethod to create a method to invoke the generic method. It seems to work for very simple cases. However implementing that for arbitrary method signatures might tricky.

Configuration

  • Which version of .NET is the code running on? 8.0
  • What OS and version, and what distro if applicable? Mac OS X 14.4
  • What is the architecture (x64, x86, ARM, ARM64)? x64
  • Do you know whether it is specific to that configuration? Not that I'm aware of
  • If you're using Blazor, which web browser(s) do you see this issue in? N/A
~/Repos/MinRepro > dotnet --info
.NET SDK:
 Version:           8.0.203
 Commit:            5e1ceea679
 Workload version:  8.0.200-manifests.4e94be9c

Runtime Environment:
 OS Name:     Mac OS X
 OS Version:  14.4
 OS Platform: Darwin
 RID:         osx-x64
 Base Path:   /usr/local/share/dotnet/sdk/8.0.203/

.NET workloads installed:
There are no installed workloads to display.

Host:
  Version:      8.0.3
  Architecture: x64
  Commit:       9f4b1f5d66

.NET SDKs installed:
  6.0.420 [/usr/local/share/dotnet/sdk]
  8.0.203 [/usr/local/share/dotnet/sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 6.0.28 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 8.0.3 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 6.0.28 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
  Microsoft.NETCore.App 8.0.3 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]

Other architectures found:
  None

Environment variables:
  Not set

global.json file:
  Not found

Learn more:
  https://aka.ms/dotnet/info

Download .NET:
  https://aka.ms/dotnet/download

Other information

🤷

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions