问题描述
我需要就如何实施以下内容提出建议或想法。我有一个接口有很多方法,每个方法都可以抛出异常(实际上它是 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 ...