c# reflein: вызов метода с типом generi c и параметром generi c для данного экземпляра класса - PullRequest
0 голосов
/ 10 февраля 2020

Мне нужно вызвать метод generi c с параметром generi c, используя отражение, где тип generi c предоставляется в качестве параметра в строке. В Интернете есть несколько примеров обобщений и рефлексии, но я все еще не могу заставить это работать.

Без рефлексии:

        string typeName = "EventType"; // as param1 -> type name
        string content = ""; //as param2 -> some json cotnent

        IMyBus bus = new MyBus();
        switch (typeName)
        {
            case "EventType":
                IEventType content = Deserialize<IEventType>(content);
                bus.Publish<IEventType>(content);
                break;
            case "EventType2":
                IEventType2 content2 = Deserialize<IEventType2>(content);
                bus.Publish<IEventType2>(content2);
                break;
        }

Вместо этого я хотел бы переписать его, используя рефлексию, чтобы предоставить больше EventTypes без переписывания этого конкретного кода.

Ниже приведены мои тестовые классы:

 public interface IMyBus **//TWO METHODS HERE, WE NEED TO CALL FIRST ONE!**
 {
     void Publish<T>(T message, CancellationToken cancellationToken = default(CancellationToken)) where T : class; //THIS SHOULD BE CALLED
     void Publish<T>(T message, int i, CancellationToken cancellationToken = default(CancellationToken)) where T : class;
  }

  // Interface implementation
  public class MyBus : IMyBus
  {
      public void Publish<T>(T message, CancellationToken cancellationToken = default(CancellationToken)) where T : class
      {  ... }
      public void Publish<T>(T message, int i, CancellationToken cancellationToken = default(CancellationToken)) where T : class
      {  ... }
    }

    public interface IEventType { int forTest { get; set; } }

    public class EventType : IEventType { public int forTest { get; set; } }

    public interface IEventType2 { int forTest2 { get; set; } }

    public class EventType2 : IEventType2 { public int forTest2 { get; set; } }

И вот что я уже попробовал:

 IMyBus bus = new MyBus();
 EventType content = new EventType() { forTest = 1 };
 var eventTypeName = $"ConsoleApp.EventType";
 var iEventTypeName = $"ConsoleApp.IEventType";

 Type intEvType = Type.GetType(iEventTypeName);
 Type evType = Type.GetType(eventTypeName);

 MethodInfo openGenericMethod = typeof(IMyBus).GetMethod("Publish", 2, new Type[] { intEvType, typeof(CancellationToken) });
 MethodInfo closedGenericMethod = openGenericMethod.MakeGenericMethod(evType);
 object o2 = closedGenericMethod.Invoke(bus, new object[] { content });

Но это неправильно. openGenericMethod всегда равно нулю.

1 Ответ

1 голос
/ 11 февраля 2020

Я думаю, что для этой ситуации лучше найти метод вручную на основе имени и количества параметров:


 MethodInfo openGenericMethod = typeof(IMyBus).GetMethods()
                                .SingleOrDefault(m => m.Name == "Publish" 
                                                && m.IsGenericMethod 
                                                && m.GetParameters().Count() == 2);


Но вы собираетесь вызывать метод с optional параметрами. Вот почему вы должны использовать другой метод Invoke, в котором вы можете определить флаг привязки:

MethodInfo closedGenericMethod = openGenericMethod.MakeGenericMethod(evType);

closedGenericMethod.Invoke(bus, BindingFlags.OptionalParamBinding, null, 
new object[] { content, Type.Missing }, CultureInfo.InvariantCulture);

Я тестировал его в тесте ConsoleApp. Это работает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...