首页 > 解决方案 > 当具有相似的方法代码但调用者名称发生变化时使用什么方法?

问题描述

我正在设计一个类,它只是包装了一些方法调用,这些方法调用是另一个类库的一部分。

这是我的班级的样子:

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

我看到的一个缺点是,假设如果正在使用的库将来发布新版本并且方法名称有任何更改,它不会在我使用反射时给出任何编译错误,但在运行时,它会抛出异常。

这种方法有更好的替代解决方案吗?

另外,有什么方法可以在有/没有反射的情况下进一步优化我的代码?

标签: c#.net.net-standard

解决方案


您可以将反射缓存MethodInfo到 aDictionary<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>();
}

MyClass此外,您可以使用nameof表达式消除每个公共方法中的反射。

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

或者,当然,如果您的第三方依赖项更改了方法的名称,那么您仍然会遇到一个问题,即表现为运行时错误而不是编译时错误。因此,您可以通过使用nameofon 方法的名称来解决此问题IService

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

现在,如果IService更改了方法名称,则会出现编译器错误。

这应该比您的示例在性能方面得到更好的优化。除了......你在这一点上得到了什么?on 上的每个公共方法MyClass仍然必须直接引用它对应的 on 方法IService。IE,MyClass.MethodA直接引用IService.MethodA。那么,为什么不直接调用Service.MethodA并为自己节省反射的复杂性和性能成本呢?

此外,您担心您的第三方依赖项会更改方法名称以及创建运行时错误而不是编译时错误,此处概述的方法应该可以解决这个问题。但是,如果您的第三方依赖项更改了方法的签名怎么办?EG,IService.MethodA()变成IService.MethodA(string param1)? 现在你又回到了运行时异常而不是编译器错误的问题上。

我知道您发布的内容只是一个示例,仅基于示例,我无法理解您尝试做的事情的完整背景。但是,基于那个例子,我认为最好MyClass的版本是没有反射的版本。我真的很难看到通过使用反射调用IService而不是直接调用方法来获得什么。


推荐阅读