动态调用方法

本文关键字:方法 调用 动态 | 更新日期: 2023-09-27 17:59:55

我有一个WCF服务,它公开了一组对各种类型的集合执行操作的[OperationContract]

现在几乎每个实现都是这样的:

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

因此,虽然this.PerformSomeOperation(...)部分在实际实现之间发生了变化,但骨架的其余部分保持不变。因此提出了动态注入this.PerformSomeOperation(...)部分的思想。

对此,最优雅的解决方案是什么?当然,我可以将要执行的操作的方法名作为字符串传递到外部方法的参数列表中,并使用反射来调用该方法(.GetMethod(...)),但我希望得到一些优雅的Lambda或Delegate构造。

动态调用方法

为什么不使用委托?这些基本上是函数指针。

所以你有了你的通用DoWork方法和一个动作:

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

然后用指向自己的函数PerformSomeOperation 的指针调用它

DoWork(PerformSomeOperation);

现在,您可以切换可以使用的方法。

DoWork(PerformOtherOperationWithSameSignature)

在这种情况下,Template方法模式似乎很方便。

您定义包含方法骨架的基类如下:

public abstract class AbstractProcessor<T>
{
    public void ProcessData(List<T> data)
    {
        var exceptions = new List<Exception>();
        foreach (var item in data)
        {
            try
            {
                ProcessDataInternal(item);
            }
            catch (Exception exception)
            {
                exceptions.Add(exception);
            }
        }
        if (exceptions.Count > 0) throw new AggregateException(exceptions);
    }
    protected abstract void ProcessDataInternal(T data);
}

然后您应该定义具体的实现并覆盖ProcessDataInternal方法:

public class ConcreteProcessor<T> : AbstractProcessor<T>
{
    protected override void ProcessDataInternal(T data)
    {
        // This implementation simply writes data to the console.
        Console.WriteLine(data);
    }
}

客户端示例:

AbstractProcessor<string> processor = new ConcreteProcessor<string>();
processor.ProcessData(new List<string> { "Hello", "World" });

使用辅助方法

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

或者使用扩展方法:

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

加入一些泛型(支持所有类型):

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