Search code examples
c#reflectioncode-reusereusability

Dynamically invoke method


I have a WCF service that exposes a bunch of [OperationContract]s that perform operations on collections of various types.

Now almost every implementation looks like this:

        public void PerformSomeOperation(List<SomeType> someCollection) {
        // store the exceptions that might be thrown during the operation
        var exceptions = new List<Exception>();

        foreach (var item in someCollection) {
            try {
                this.PerformSomeOperation(someParameters);
            }
            catch (Exception exception) {
                exceptions.Add(exception);
            }
        }

        // Throw the exceptions here after the loop completes. 
        if (exceptions.Count > 0) throw new AggregateException(exceptions);
    }

So, while the this.PerformSomeOperation(...) part changes between the actual implementations, the rest of the skeleton remains the same. Hence the idea to dynamically inject the this.PerformSomeOperation(...) part.

What is the most elegant solution to this? Of course I could pass in the method name of the operation to be performed as string in the outer method's parameter list and use reflection to call the method (.GetMethod(...)) but I was hoping for some elegant Lambda or Delegate construct.


Solution

  • Use a helper method

    public void YourServiceMethod()
    {
        var collection = GetSomeDate();
        DoWork(collection, item => PerformSomeOperation(someParameters));
    }
    
    private void DoWork(List<SomeType> collection, Action<SomeType> itemProcessor)
    {
       var exceptions = new List<Exception>();
    
        foreach (var item in collection) 
        {
            try 
            {
                itemProcessor(someParameters);
            }
            catch (Exception exception) 
            {
                exceptions.Add(exception);
            }
        }
    
        // Throw the exceptions here after the loop completes. 
        if (exceptions.Count > 0) throw new AggregateException(exceptions);
    }
    

    Or use an extension method:

    public void YourServiceMethod()
    {
        var collection = GetSomeDate();
        collection.DoWork(item => PerformSomeOperation(someParameters));
    }
    
    public class ListExtensions
    {
        public void DoWork(this List<SomeType> collection, Action<SomeType> itemProcessor)
        {
           var exceptions = new List<Exception>();
    
            foreach (var item in collection) 
            {
                try 
                {
                    itemProcessor(someParameters);
                }
                catch (Exception exception) 
                {
                    exceptions.Add(exception);
                }
            }
    
            // Throw the exceptions here after the loop completes. 
            if (exceptions.Count > 0) throw new AggregateException(exceptions);
        }
    }
    

    Throw in some generics (to support all types):

    public void YourServiceMethod()
    {
        var collection = GetSomeDate();
        collection.ProcessList(item => PerformSomeOperation(someParameters));
    }
    
    public class ListExtensions
    {
        public void ProcessList<T>(this IEnumerable<T> collection, Action<T> itemProcessor)
        {
           var exceptions = new List<Exception>();
    
            foreach (var item in collection) 
            {
                try 
                {
                    itemProcessor(someParameters);
                }
                catch (Exception exception) 
                {
                    exceptions.Add(exception);
                }
            }
    
            // Throw the exceptions here after the loop completes. 
            if (exceptions.Count > 0) throw new AggregateException(exceptions);
        }
    }