简体   繁体   English

动态调用方法

[英]Dynamically invoke method

I have a WCF service that exposes a bunch of [OperationContract] s that perform operations on collections of various types. 我有一个WCF服务,它公开了一堆[OperationContract] ,它们对各种类型的集合执行操作。

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. 因此,尽管this.PerformSomeOperation(...)部分在实际实现之间发生了变化,但其余部分保持不变。 Hence the idea to dynamically inject the this.PerformSomeOperation(...) part. 因此,想到了动态注入this.PerformSomeOperation(...)部分的想法。

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. 当然,我可以在外部方法的参数列表中传入要作为字符串执行的操作的方法名称,并使用反射来调用该方法( .GetMethod(...) ),但是我希望有一些优雅的Lambda或Delegate构造。

Why not use delegates ? 为什么不使用委托 These are basically function pointers. 这些基本上是函数指针。

So you have your general DoWork method with an Action : 因此,您可以使用带有Action的常规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);
  }

And then call it with a pointer to your own function PerformSomeOperation 然后使用指向您自己的函数PerformSomeOperation的指针进行调用

DoWork(PerformSomeOperation);

Now you are able to switch the methods you can use. 现在,您可以切换可以使用的方法。

DoWork(PerformOtherOperationWithSameSignature)

It looks like the Template method pattern could be handy in this situation. 在这种情况下,看起来Template方法模式很方便。

You define your base class that contains method skeleton as following: 您定义包含方法框架的基类,如下所示:

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

Then you should define concrete implementations and override ProcessDataInternal method: 然后,您应该定义具体的实现并覆盖ProcessDataInternal方法:

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

Client example: 客户示例:

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM