Какой подход использовать при наличии аналогичного кода метода, но только с изменением имени вызывающего абонента? - PullRequest
0 голосов
/ 17 июня 2020

Я разрабатываю класс, который просто объединяет вызовы нескольких методов, которые являются частью другой библиотеки классов.

Вот как выглядит мой класс:

public class MyClass
{
    IService Service; //Third Party Library.

    public MyClass()
    {
        // Initialization
    }

    public string MethodA()
    {
        Service.MethodA();
        return Service.GetResult();
    }

    public string MethodB()
    {
        Service.MethodB();
        return Service.GetResult();
    }

    public string MethodC()
    {
        Service.MethodC();
        return Service.GetResult();
    }

    public string MethodD()
    {
        Service.MethodD();
        return Service.GetResult();
    }
}

С помощью отражение Я отредактировал приведенный выше код в некоторой степени, как показано ниже:

public class MyClass
{
    IService Service;

    public MyClass()
    {
        // Initialization
    }

    public string MethodA()
    {
       return GetResult(System.Reflection.MethodBase.GetCurrentMethod().Name);
    }

    public string MethodB()
    {
       return GetResult(System.Reflection.MethodBase.GetCurrentMethod().Name);
    }

    public string MethodC()
    {
       return GetResult(System.Reflection.MethodBase.GetCurrentMethod().Name);
    }

    public string MethodD()
    {
       return GetResult(System.Reflection.MethodBase.GetCurrentMethod().Name);
    }

    private string GetResult(string methodName)
    {
       Service.GetType().GetMethods().FirstOrDefault(x => x.Name == methodName).Invoke(Service, null);
       return Service.GetResult();
    }
}

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

Есть ли лучшее альтернативное решение для этого подхода?

Кроме того, Можно ли как-нибудь дополнительно оптимизировать свой код с отражением / без отражения?

Ответы [ 2 ]

1 голос
/ 17 июня 2020

Вы можете кэшировать отраженный MethodInfo в Dictionary<string, MethodInfo>, чтобы вам не приходилось искать его каждый раз, когда вы вызываете MyClass.GetResult(string methodName).

public class MyClass
{
   private string GetResult(string methodName)
   {
      if (!_methods.TryGetValue(methodName, out MethodInfo method))
      {
         method = typeof(IService).GetMethods().FirstOrDefault(x => x.Name == methodName);
         _methods.Add(methodName, method);
      }
      method.Invoke(Service, null);
      return Service.GetResult();
   }

   private static readonly Dictionary<string, MethodInfo> _methods = new Dictionary<string, MethodInfo>();
}

Кроме того, вы можете удалить отражение в каждом из методов publi c в MyClass, используя nameof выражение .

public class MyClass
{
   public string MethodA()
   {
      return GetResult(nameof(MethodA));
   }
}

Или, конечно, если ваша сторонняя зависимость изменяет имя метода тогда у вас все еще есть проблема, когда это проявляется как ошибка времени выполнения, а не ошибка времени компиляции. Итак, вы можете исправить это, используя nameof с именем метода на IService.

public class MyClass
{
   public string MethodA()
   {
      return GetResult(nameof(IService.MethodA));
   }
}

Теперь, если имя метода на IService изменится, вы получите ошибку компилятора.

Это должно быть лучше оптимизировано с точки зрения производительности, чем ваш пример. Кроме ... чего ты добился на данный момент? Каждый метод publi c на MyClass по-прежнему должен напрямую ссылаться на соответствующий метод на IService. IE, MyClass.MethodA напрямую ссылается на IService.MethodA. Итак, почему бы просто не вызвать Service.MethodA и сэкономить сложность и затраты на производительность, связанные с отражением?

Кроме того, вы обеспокоены тем, что ваша сторонняя зависимость изменяет имя метода и создает ошибки времени выполнения вместо времени компиляции ошибки и описанный здесь подход должны решить эту проблему. Но что, если ваша сторонняя зависимость изменяет подпись метода? Например, IService.MethodA() становится IService.MethodA(string param1)? Теперь вы вернулись к исходной точке с исключениями времени выполнения вместо ошибок компилятора.

Я понимаю, что то, что вы опубликовали, является просто примером, и что я не могу понять полный контекст того, что вы пытаетесь сделать, основываясь только на примере. Но, основываясь на этом примере, на мой взгляд, лучшая версия MyClass - это версия без отражения . Я действительно изо всех сил пытаюсь понять, что вы получите, используя отражение для вызова IService, а не просто вызывая методы напрямую.

0 голосов
/ 17 июня 2020

Я бы go с любым из двух представленных вами вариантов добавил модульные тесты, чтобы проверить, есть ли в версии сторонней библиотеки, которая используется для этой конкретной сборки, эти методы. Фактически вы можете использовать некоторое отражение и go довольно глубоко с этими модульными тестами, например, для проверки того, совпадают ли сигнатуры методов и т. Д. Эти модульные тесты гарантируют, что ваша сборка не удастся, если эти методы в сторонней библиотеке изменились. это время жизни.

PS Отражение вообще довольно медленное. Если вы выберете второй вариант, вы можете захотеть провести сравнение производительности между первым и вторым вариантами, прежде чем реализовывать его. Наличие этих модульных тестов означает, что нет необходимости использовать второй вариант.

PS2. Я бы написал комментарий вместо поста, но у меня недостаточно репутации

...