开放通用接口方法的委托

naa*_*ing 23 c# generics delegates

我正在尝试为通用接口方法创建一个打开的实例委托,但我一直收到NotSupportedException.以下是无法运行的简化代码:

interface IFoo
{
    void Bar<T>(T j);
}
class Foo : IFoo
{
    public void Bar<T>(T j)
    {
    }
}
static void Main(string[] args)
{
    var bar = typeof(IFoo).GetMethod("Bar").MakeGenericMethod(typeof(int));
    var x = Delegate.CreateDelegate(typeof(Action<IFoo, int>), null, bar);
}
Run Code Online (Sandbox Code Playgroud)

最后一行抛出NotSupportedException,"不支持指定的方法".相比之下,非通用的开放实例委托运行良好:

interface IFoo
{
    void Bar(int j);
}
class Foo : IFoo
{
    public void Bar(int j)
    {
    }
}
static void Main(string[] args)
{
    var bar = typeof(IFoo).GetMethod("Bar");
    var x = Delegate.CreateDelegate(typeof(Action<IFoo, int>), null, bar);
}
Run Code Online (Sandbox Code Playgroud)

封闭的通用委托也有效:

interface IFoo
{
    void Bar<T>(T j);
}
class Foo : IFoo
{
    public void Bar<T>(T j)
    {
    }
}
static void Main(string[] args)
{
    var bar = typeof(IFoo).GetMethod("Bar").MakeGenericMethod(typeof(int));
    var x = Delegate.CreateDelegate(typeof(Action<int>), new Foo(), bar);
}
Run Code Online (Sandbox Code Playgroud)

因此,封闭的通用委托和开放实例委托的配方分开工作,但在组合时则不然.它开始看起来像运行时错误或故意遗漏.有人有任何见解吗?

Mic*_*ael 5

这是该主题的概述,也是针对发现此问题的人员的特定问题(因为OP似乎已经在Microsoft Connect上得到了答案)。


回答

为通用接口方法创建开放实例通用委托是不可能的(如Microsoft 此处确认)。当前,可以实现以下任何一种打开/关闭静态,通用/非通用,接口/类方法的组合(答案末尾提供了代码示例):

  • 非泛型接口方法的开放实例非泛型委托
  • 通用接口方法的封闭静态通用委托
  • 非通用接口方法的封闭静态非通用委托
  • 通用类方法的开放实例通用委托
  • 非泛型类方法的开放实例非泛型委托
  • 通用类方法的封闭静态通用委托
  • 非泛型类方法的封闭静态非泛型委托

通常,通用接口方法的开放实例通用委托的最佳替代方法是通用方法的开放实例通用委托。


代码样例

  • 非泛型接口方法的开放实例非泛型委托

    interface IFoo
    {
      void Bar(int j);
    }
    
    class Foo : IFoo
    {
      public void Bar(int j)
      {
      }
    }
    
    static void Main(string[] args)
    {
      var bar = typeof(IFoo).GetMethod("Bar");
      var x = Delegate.CreateDelegate(typeof(Action<IFoo, int>), null, bar);
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 通用接口方法的封闭静态通用委托

      interface IFoo
      {
        void Bar<T>(T j);
      }
    
      class Foo : IFoo
      {
        public void Bar<T>(T j)
        {
        }
      }
    
      static void Main(string[] args)
      {
        var bar = typeof(IFoo).GetMethod("Bar").MakeGenericMethod(typeof(int));
        var x = Delegate.CreateDelegate(typeof(Action<int>), new Foo(), bar);
      }
    
    Run Code Online (Sandbox Code Playgroud)
  • 非通用接口方法的封闭静态非通用委托

      interface IFoo
      {
        void Bar(int j);
      }
    
      class Foo : IFoo
      {
        public void Bar(int j)
        {
        }
      }
    
      static void Main(string[] args)
      {
        var bar = typeof(IFoo).GetMethod("Bar");
        var x = Delegate.CreateDelegate(typeof(Action<int>), new Foo(), bar);
      }
    
    Run Code Online (Sandbox Code Playgroud)
  • 通用类方法的开放实例通用委托

    class Foo
    {
        public void Bar<T>(T j)
        {
        }
    }
    
    static void Main(string[] args)
    {
        var bar = typeof(Foo).GetMethod("Bar").MakeGenericMethod(typeof(int));
        var x = Delegate.CreateDelegate(typeof(Action<Foo, int>), null, bar);
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 非泛型类方法的开放实例非泛型委托

    class Foo
    {
        public void Bar(int j)
        {
        }
    }
    
    static void Main(string[] args)
    {
        var bar = typeof(Foo).GetMethod("Bar");
        var x = Delegate.CreateDelegate(typeof(Action<Foo, int>), null, bar);
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 通用类方法的封闭静态通用委托

    class Foo
    {
        public void Bar<T>(T j)
        {
        }
    }
    
    static void Main(string[] args)
    {
        var bar = typeof(Foo).GetMethod("Bar").MakeGenericMethod(typeof(int));
        var x = Delegate.CreateDelegate(typeof(Action<int>), new Foo(), bar);
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 非泛型类方法的封闭静态非泛型委托

    class Foo
    {
        public void Bar(int j)
        {
        }
    }
    
    static void Main(string[] args)
    {
        var bar = typeof(Foo).GetMethod("Bar");
        var x = Delegate.CreateDelegate(typeof(Action<int>), new Foo(), bar);
    }
    
    Run Code Online (Sandbox Code Playgroud)


naa*_*ing 0

微软已经回答说,CLR 无法做到这一点是一个已知问题,但在当前版本的 .NET 中无法解决。正如我在那里解释的那样,仍然不清楚为什么这是不可能的。由于某种原因,开放委托不得重用 CLR 中其他地方使用的调度逻辑,这对我来说似乎很奇怪。