I am designing a class which is just wrapping a few methods calls which are part of another class library.
Here's what my class looks like:
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();
}
}
With the help of reflection I have refactored above code to some extent as below:
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();
}
}
One drawback that I am seeing is that suppose if the library which am using release new version in the future and if there are any changes in the method name, it will not give any compilation error as I am using reflection, but at runtime, it will throw an exception.
Is there any better alternative solution to this approach?
Also, is there any way I can optimize my code further with/without reflection?
You could cache the reflected MethodInfo
into a Dictionary<string, MethodInfo>
so you don't have to look it up every time you call 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>();
}
Furthermore, you could eliminate the reflection in each of the public methods in MyClass
by using the nameof
expression.
public class MyClass
{
public string MethodA()
{
return GetResult(nameof(MethodA));
}
}
Or course, if your third party dependency changes the name of a method then you still have a problem where that manifests itself as a runtime error instead of a compile time error. So, you could fix that by using nameof
with the name of the method on IService
.
public class MyClass
{
public string MethodA()
{
return GetResult(nameof(IService.MethodA));
}
}
Now, if a method name on IService
changes you get a compiler error.
This should be better optimized in terms of performance than your example. Except... what have you gained at this point? Each public method on MyClass
still has to directly reference it's corresponding method on IService
. I.E., MyClass.MethodA
directly references IService.MethodA
. So, why not just call Service.MethodA
and save yourself the complexity and performance costs of reflection?
Furthermore, you're concerned about your third party dependency changing a method name and that creating runtime errors instead of compile time errors and the approach outlined here should address that. But, what if your third party dependency changes a method's signature? E.G., IService.MethodA()
becomes IService.MethodA(string param1)
? Now you're right back to square one with runtime exceptions instead of compiler errors.
I understand what you've posted is just an example, and that I can't understand the full context of what you're trying to do based on just an example. But, based on that example, in my opinion the best version of MyClass
is the version without reflection. I'm really struggling to see what you gain by using reflection to call into IService
rather than just calling the methods directly.