How to make a reference to a method name on a strongly typed interface

Sorry if this has already been answered, but I think that I don’t have enough formal education to ask this question correctly, and therefore, I don’t have the right criteria for its successful search.

I have an API that has several calls that do almost the same thing, but act on different input objects using a different method, but always form the same interface. I want to cut and paste an aspect from the processes of an API method call so that the generic code gets the same in all method calls. I managed to get a working solution using generics for input and output objects, and I make a reference to the name of the method that is called from the string. I would like method references to be strongly typed, not line-based, so renaming the method name when re-factoring would not potentially leave a “magic” string for the method name that expects to explode at run time.

Below is a very simplified version of what I'm trying to achieve.

class ARequest { }; class AResponse { }; class BRequest { }; class BResponse { }; interface IWorker { AResponse DoA(ARequest aRequest); BResponse DoB(BRequest bRequest); } class Worker : IWorker { public AResponse DoA(ARequest aRequest) { return new AResponse(); } public BResponse DoB(BRequest bRequest) { return new BResponse(); } } class Program { static void Main(string[] args) { // current concrete copy & paste implementation var a1 = API.DoA(new ARequest { }); var b1 = API.DoB(new BRequest { }); // new generic implementation var a2 = API.DoA2(new ARequest { }); var b2 = API.DoB2(new BRequest { }); } } static class API { // current concrete copy & paste implementation public static AResponse DoA(ARequest aRequest) { // lots of common code for logging & preperation var worker = GetWorker(); return worker.DoA(aRequest); } public static BResponse DoB(BRequest bRequest) { // lots of common code for logging & preperation var worker = GetWorker(); return worker.DoB(bRequest); } private static IWorker GetWorker() { return new Worker(); } // new generic implementation Attempt public static AResponse DoA2(ARequest aRequest) { return DoGen<ARequest, AResponse>(aRequest, "DoA"); // how to make references to DoA and DoB methods on the IWorker strongly typed? } public static BResponse DoB2(BRequest bRequest) { return DoGen<BRequest, BResponse>(bRequest, "DoB"); // how to make references to DoA and DoB methods on the IWorker strongly typed? } public static TResponse DoGen<TRequest, TResponse>(TRequest requestObj, string methodname) where TRequest : class where TResponse : class { // lots of common code for logging & preperation var worker = GetWorker(); var mi = worker.GetType().GetMethod(methodname); var result = mi.Invoke(worker, new Object[] { requestObj }); return result as TResponse; } } 
+4
source share
4 answers

The magic string for the delegate delegate method name

  public static AResponse DoA2(ARequest aRequest) { return DoGen<ARequest, AResponse>(aRequest, worker => worker.DoA); } public static BResponse DoB2(BRequest bRequest) { return DoGen<BRequest, BResponse>(bRequest, worker => worker.DoB); } public static TResponse DoGen<TRequest, TResponse>(TRequest requestObj, Func<IWorker, Func<TRequest, TResponse>> methodRef) where TRequest : class where TResponse : class { // lots of common code for logging & preparation var worker = GetWorker(); var method = methodRef(worker); return method(requestObj); } 
+2
source

Func <xRequest, xResponse> can do what you are looking for:

  var a1 = new Func<ARequest, AResponse>(API.DoA); var b1 = new Func<BRequest, BResponse>(API.DoB); var a2 = new Func<ARequest, AResponse>(API.DoA2); var b2 = new Func<BRequest, BResponse>(API.DoB2); a1.Invoke(new ARequest { }); b1.Invoke(new BRequest { }); a2.Invoke(new ARequest { }); b2.Invoke(new ARequest { }); // fails at compile time 
+1
source

Add delegate for mehods:

  public delegate TResponse DoXDelegate<in TRequest, out TResponse>(TRequest request); public static TResponse DoGen<TRequest, TResponse>(TRequest requestObj, DoXDelegate<TRequest, TResponse> method) where TRequest : class where TResponse : class { // lots of common code for logging & preperation var worker = GetWorker(); /*var mi = worker.GetType().GetMethod(methodname); var result = mi.Invoke(worker, new Object[] { requestObj }); return result as TResponse;*/ return method.Invoke(requestObj); } 
0
source

Use Func<TRequest, TResponse> as follows:

Edit: This example solution can only be used if it doesn't matter where the work object comes from.

 // new generic implementation Attempt public static AResponse DoA2(ARequest aRequest) { return DoGen<ARequest, AResponse>(aRequest, DoA); // how to make refreces to DoA and DoB methods strongly typed? } public static BResponse DoB2(BRequest bRequest) { return DoGen<BRequest, BResponse>(bRequest, DoB); // how to make refreces to DoA and DoB methods strongly typed? } public static TResponse DoGen<TRequest, TResponse>(TRequest requestObj, Func<TRequest, TResponse> func) where TRequest : class where TResponse : class { // lots of common code for logging & preperation var result = func(requestObj); return result as TResponse; } 
0
source

Source: https://habr.com/ru/post/1399768/


All Articles