在按对象迭代的循环中按名称调用方法,寻找设计模式

Call method by name in loop iterating by objects, looking for design pattern

我需要关于如何实施以下内容的建议或想法。我有一个包含许多方法的接口,每个方法都可以抛出异常(实际上它是 WCF 调用)。所以每个调用 必须 由 try 块

包装
public interface ISomeInterface
{
 MethodThatCanThrow1(Arg1 arg);
 ..
 MethodThatCanThrow101(Arg2 arg);
}

现在我们有了对象集合

var items = new List<ISomeInterface>();

现在我必须为每个对象循环调用 MethodThatCanThrow1 方法。方法可以抛出异常,在那种情况下我需要继续剩余的对象

void CallMethodThatCanThrow1()
{ 
 foreach(var item in items)
 {
  try
  {
    item.MethodThatCanThrow1(Arg1 arg);
  }
  catch(Exception ex)
  {
   // do something
  }
 }
}

现在我需要调用 MethodThatCanThrow2 所以对于第二种方法我需要复制粘贴 try catch 块内容。

void CallMethodThatCanThrow2()
{ 
 foreach(var item in items)
 {
  try
  {
    item.MethodThatCanThrow2(Arg2 arg);
  }
  catch(Exception ex)
  {
   // remove failed item from items
   // continue foreach for the rest
  }
 }
}

所以对于其余的 101 方法,我必须复制粘贴整个块,只更改方法名称。

所以我正在考虑重构它。我想要的是将try catch块放在单独的Method中并传递需要调用的方法名称

void CallMethodofISomeInterfaceForGivenReference(delegate methodProvide)
{ 
 foreach(var item in items)
 {
  try
  {
     // take item and call method that is provided
  }
  catch(Exception ex)
  {
   // do something
  }
 }
}

正如评论中已经建议的那样:我不使用反射和方法名称,而是使用委托。

假设您的接口有很多这种形式的方法:

public interface ISomeInterface
{
  void MethodThatCanThrow1(Arg1 arg);
   ..
  void MethodThatCanThrow101(Arg2 arg);
}

你可以做一个小帮手:

void TryCatchWrap<TParam1>( Action<TParam1> action, TParam1 param1, Action<Excpetion> handleException )
{
    try
    {
        action(param1);
    }
    catch(Exception ex)
    {
        handleException(ex)
    }
}

将被称为:

foreach( var item in collection )
{
    tryCatchWrap<Arg1>( item.MethodThatCanThrow1, arg, HandleException )
}

...,其中 HandleException 将是在该上下文中可用的 void HandleException(Exception ex)


您也可以轻松地将其适应多个参数、参数列表或函数:

TResult TryCatchWrap<TParam1, TResult>( Func<TParam1, TResult> action, TParam1 param1, Action<Excpetion> handleException )
{
    try
    {
        return action(param1);
    }
    catch(Exception ex)
    {
        handleException(ex)
    }
    return default(TResult); // in case of Exception.
}

出于好奇,我尝试了是否能够将循环放入 try

这是我得到的:

using System;
using System.Linq;
using System.Linq.Expressions;
using System.Collections.Generic;
                    
public class Program
{
    public static void Main()
    {
        Arg1 arg = new Arg1();
        // Some test data
        IList<IMyType> list = Enumerable
                               .Range(0, 42)
                               .Select(x => (IMyType)new MyType(x))
                               .ToList();
        
        var p = new Program();
        p.CollectionTryParseWrapper<IMyType, Arg1>(list, arg,          
                              (item, argument) => item.DoSomething(argument));
    }
    
    // Pass Expression instead of delegate so we can loop.
    // Pass argument awkwardly to avoid closure.
    public void CollectionTryParseWrapper<TInterface, TArgument>(
                                                IList<TInterface> list,
                                                TArgument arg1,
                                                Expression<Action<TInterface, TArgument>> expr)
    {
        // compile the Expression to an executable delegate
        var exec = expr.Compile();
        // In case of Exception, we need to know where to continue.
        int index = 0;
        // Just loop
        while(index < list.Count){
            try
            {
                for( ; index < list.Count; index++ )
                {
                    exec(list[index], arg1); // execute
                }
            }
            catch(Exception ex)
            {
                // handle ex
                Console.WriteLine("Exception" + ex.Message);
            }
            finally
            {
                index++; // advance index!!
            }
        }
    }
}

public interface IMyType
{
    void DoSomething(Arg1 arg);
}

public class Arg1 {
    public bool ShouldThrow(int index) => index % 5 == 0;
}

public class MyType : IMyType
{
    private readonly int _index;

    public MyType(int index)
    {
         this._index = index;
    }

    public void DoSomething(Arg1 arg)
    {
         if( arg.ShouldThrow(_index) ) throw new Exception($" at index {_index}");
         Console.WriteLine($"Executing #{_index:#0}");
    }
}

输出:

Exception at index 0
Executing #01
Executing #02
Executing #03
Executing #04
Exception at index 5
Executing #06
Executing #07
Executing #08
Executing #09
Exception at index 10
Executing #11
Executing #12
Executing #13
...

实际操作:https://dotnetfiddle.net/WjoSZF