Question

I'm not sure how to best describe what I want so I'm going to start off high-level and then go over my thought on the implementation.

Using c# I'm trying to make a method that has a generic return type, and takes as a parameter a method from a service reference.

This generic method is going to new up the service reference, call the service reference's method that I passed in, do all the error handling and checking needed for a service reference, and then either Close or Abort it and return the result of the call.

The sort of pseudo code of this:

public T CallServiceReference<T>(method serviceRefMethod) {
  T result = null;
  ServiceReference svcClient = new ServiceReference.Client();
    try {
      result = svcClient.serviceRefMethod;
      svcClient.Close();   
    } catch (ExceptionType ex) {
      // log error message
      svcClient.Abort();
      throw;
    }
  return result;
}

Is this possible in c#? I'm looking in generics and delegates. One of my major issues is making a delegate of one the service reference's methods without the service ref being instantiated. If I have to instantiate the service ref I think I might as well put all of the Close, Abort and error handling for each method call.

I'm researching different design patterns although it's a little difficult since I don't know the name of the one I'm looking for or if it even exists.

Let me know if I can provide any additional information or clarification.

Update (part 2): Now I'm trying to make a delegate that encapsulates variables with the method it is calling.

public delegate T Del<T>();
public static IEnumerable<String> GetDataFromService(String username) {
    ServiceReference.ServiceClient client = new ServiceReference.ServiceClient();
    // the method I'm going to call returns a string array
    Del<String[]> safeClientCall = new Del<String[]>(client.DataCall);
    // the above call is what I need to use so the C# compiles, but I want to do this
    // the below code throws an error...
    Del<String[]> safeClientCall = new Del<String[]>(client.DataCall(username));
    var result = DataCallHandlerMethod(ref client, safeClientCall);
    return result;
}

Basically pass the username parameter from my calling method and that username parameter is already defined. I don't want to define it when the delegate is invoked. Is there any way to do this using c#?

Was it helpful?

Solution

In general, everything in your answer is possible, except for this line:

result = svcClient.serviceRefMethod;

Which is obviously a crucial call... In order to dynamically invoke a function on an object you can do a few things. An easy one is to change your function signature to:

public T CallServiceReference<T>(ServiceReference svcClient, method serviceRefMethod)

but then calling code needs to new up the ServiceReference and pass in a reference to svcClient.[desiredFunction] as the serviceRefMethod.

An alternative is to change your signature to:

public T CallServiceReference<T>(string serviceRefMethodName)

and then use Reflection to find the method and invoke it. You will get no compile time validation (so if you have a typo it'll crash at runtime) but you'll get dynamic invokes. For example:

svcClient.GetType().InvokeMember(
   methodName, /* what you want to call */

   /* 
      Specifies what kinds of actions you are going to do and where / how 
      to look for the member that you are going to invoke 
    */
   System.Reflection.BindingFlags.Public | 
     System.Reflection.BindingFlags.NonPublic |
     System.Reflection.BindingFlags.Instance | 
     System.Reflection.BindingFlags.InvokeMethod, 

   null,      /* Binder that is used for binding */
   svcClient, /* the object to call the method on */
   null       /* argument list */
 );

Extra info based on your update (P.S. That probably could have been a separate question)

You now want to pass in not just a method but also the invocation of the method. Since not every method is invoked the same you are trying to do this at the call site, but that is before you actually want to invoke the method. Essentially what you're trying to do is shuttle around code that will only be executed later on (in the context of GetDataFromService).

You can either go the reflection route (in which case you pass in an object[] of parameters that you pass to the InvokeMember call or you look into Func which allows you to create some code that you run whenever you invoke the Func. For example:

 GetDataFromService(new Func<object>(() => { return client.DataCall(username); }));
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top