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

问题描述

我需要就如何实施以下内容提出建议或想法。我有一个接口有很多方法,每个方法都可以抛出异常(实际上它是 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 中并传递需要调用的 Method Name

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,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,(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