在按对象迭代的循环中按名称调用方法,寻找设计模式
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
...
我需要关于如何实施以下内容的建议或想法。我有一个包含许多方法的接口,每个方法都可以抛出异常(实际上它是 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 ...