Открытый делегат для метода универсального интерфейса

Я пытаюсь создать делегат открытого экземпляра для универсального метода интерфейса, но продолжаю получать NotSupportedException. Вот упрощенный код, который не запускается:

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

Последняя строка выдает 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), null, bar);
}

И закрытый универсальный делегат также работает:

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

Таким образом, рецепт для закрытых универсальных делегатов и делегатов открытого экземпляра работает отдельно, но не в сочетании. Это начинает выглядеть либо как ошибка времени выполнения, либо как преднамеренное упущение. У кого-нибудь есть какие-нибудь идеи?

23
задан naasking 21 August 2011 в 14:39
поделиться

2 ответа

Microsoft ответила , что это известная проблема, что CLR не может этого сделать, но она не может быть решена в текущей версии .NET. Все еще не совсем ясно , почему это невозможно, как я объясняю там. Открытые делегаты не должны повторно использовать логику диспетчеризации, используемую повсюду в CLR, по какой-то причине, что мне просто кажется странным.

0
ответ дан 29 November 2019 в 03:12
поделиться

Это резюме темы и этой конкретной проблемы для тех, кто находит этот вопрос (так как кажется, что ОП уже получил свой ответ на 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);
    }
    
  • закрыт статический универсальный делегат для универсального метода интерфейса

      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);
      }
    
  • закрытый статический неуниверсальный делегат для неуниверсального метода интерфейса

      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);
      }
    
  • универсальный делегат open instance для метода универсального класса

    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);
    }
    
  • неуниверсальный делегат open instance для метода не универсального класса

    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);
    }
    
  • закрытый статический универсальный делегат для метода универсального класса

    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);
    }
    
  • закрытый статический неуниверсальный делегат для метода не универсального класса

    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);
    }
    

5
ответ дан 29 November 2019 в 03:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: