我正在开发一种解决方案,它将连接到各种服务器以读取数据和执行操作。有许多变量使可靠通信复杂化,例如防火墙,停止/失败服务,身份验证差异和各种软件配置。我可以使用一些方法解决这些问题,但在执行时不知道哪些方法会成功。
我的目标是创建一个可用于执行操作的接口和实现。第一个方法调用将是最快的实现,适用于大多数设备,然后是其他可以处理前面列出的问题的调用。
在一个完美的世界中,将编写该过程以快速识别哪种方法会成功,但在我的测试中,处理时间与捕获异常一样多。虽然性能始终是一个考虑因素,但最终成功完成任务更为重要。
下面是我创建的一个示例,它演示了迭代实现列表的最坏情况。虽然这对于一种方法很有效,但当在20个或更多不同的操作中使用时,它不遵循DRY原则。一种可能的解决方案是Unity和Interception但我发现调用处理程序中的invoke方法使用已解析的实现,而不是可能的实现列表。除非我遗漏了某些东西,否则这似乎不是一个选择。另外,我需要为几个接口遵循这个模式,所以创建一个可以迭代实现列表的通用处理程序会很好。
有关如何完成此任务的任何建议将不胜感激!
接口
public interface IProcess
{
int ProcessItem(string workType);
}
实现
public class ProcessImplementation1 : IProcess
{
public int ProcessItem(string workType)
{
throw new TimeoutException("Took too long");
}
}
public class ProcessImplementation2 : IProcess
{
public int ProcessItem(string workType)
{
throw new Exception("Unexpected issue");
}
}
public class ProcessImplementation3 : IProcess
{
public int ProcessItem(string workType)
{
return 123;
}
}
特殊实现循环执行其他实现,直到成功无异常
public class ProcessImplementation : IProcess
{
public int ProcessItem(string workType)
{
List<IProcess> Implementations = new List<IProcess>();
Implementations.Add(new ProcessImplementation1());
Implementations.Add(new ProcessImplementation2());
Implementations.Add(new ProcessImplementation3());
int ProcessId = -1;
foreach (IProcess CurrentImplementation in Implementations)
{
Console.WriteLine("Attempt using {0} with workType '{1}'...",
CurrentImplementation.GetType().Name, workType);
try
{
ProcessId = CurrentImplementation.ProcessItem(workType);
break;
}
catch (Exception ex)
{
Console.WriteLine(" Failed: {0} - {1}.",
ex.GetType(), ex.Message);
}
Console.WriteLine();
if (ProcessId > -1)
{
Console.WriteLine(" Success: ProcessId {0}.", ProcessId);
}
else
{
Console.WriteLine("Failed!");
}
return ProcessId;
}
}
}
答案 0 :(得分:1)
您可以将处理操作实现为通用扩展方法,您可以传递对单个项目进行处理的方法:
public static int ProcessItems<T>(this IEnumerable<T> items, Func<T, int> processMethod)
{
foreach (var item in items)
{
try
{
return processMethod(item);
}
catch(Exception) {}
}
return -1;
}
现在你已经考虑了项目的实际类型以及用于处理的方法。唯一“固定”的是泛型方法的结果类型,它是一个整数。
对于您当前的示例,您可以这样调用它:
List<IProcess> implementations = ...;
int processResult = items.ProcessItems(x => x.ProcessItem(workType));
答案 1 :(得分:0)
您可以在第二个界面中使用TryParse模式:
public interface IProcess
{
int ProcessItem(string workType);
}
internal interface ITryProcess
{
bool TryProcessItem(string workType, out int result);
}
public class ProcessImplementation1 : ITryProcess
{
public bool TryProcessItem(string workType, out int result)
{
result = -1;
return false;
}
}
public class ProcessImplementation : IProcess
{
public int ProcessItem(string workType)
{
var implementations = new List<ITryProcess>();
implementations.Add(new ProcessImplementation1());
// ...
int processId = -1;
foreach (ITryProcess implementation in implementations)
{
if (implementation.TryProcessItem(workType, out processId))
{
break;
}
}
if (processId < 0)
{
throw new InvalidOperationException("Unable to process.");
}
return processId;
}
}
答案 2 :(得分:0)
这是一个类似于@BrokenGlass创建的解决方案,如果你想要一些非常简单和“通用”的东西。
public void TryAllImplementations<TService>(
IEnumerable<TService> services,
Action<TService> operation,
Action<Exception> exceptionHandler = null)
{
int dummy = 0;
TryAllImplementations(
services,
svc => { operation(svc); return dummy; },
exceptionHandler);
}
public TReturn TryAllImplementations<TService, TReturn>(
IEnumerable<TService> services,
Func<TService, TReturn> operation,
Action<Exception> exceptionHandler = null)
{
foreach (var svc in services)
{
try
{
return operation(svc);
}
catch (Exception ex)
{
if (exceptionHandler != null)
exceptionHandler(ex);
}
}
throw new ProgramException("All implementations have failed.");
}
由于我看到Unity标记,您可以使用服务接口在容器上使用ResolveAll<TService>()
来获取所有实现。将其与此代码相结合,您可以在IUnityContainer
上执行类似扩展方法的操作:
public static class UnityContainerExtensions
{
public static void TryAllImplementations<TService>(
this IUnityContainer container,
Action<TService> operation,
Action<Exception> exceptionHandler = null)
{
int dummy = 0;
container.TryAllImplementations<TService, int>(
svc => { operation(svc); return dummy; },
exceptionHandler);
}
public static TReturn TryAllImplementations<TService, TReturn>(
this IUnityContainer container,
Func<TService, TReturn> operation,
Action<Exception> exceptionHandler = null)
{
foreach (var svc in container.ResolveAll<TService>())
{
try
{
return operation(svc);
}
catch (Exception ex)
{
if (exceptionHandler != null)
exceptionHandler(ex);
}
}
throw new ProgramException("All implementations have failed.");
}
}
以下是使用它的方法:
IUnityContainer container;
// ...
container.RegisterType<IProcess, ProcessImplementation1>();
container.RegisterType<IProcess, ProcessImplementation2>();
container.RegisterType<IProcess, ProcessImplementation3>();
// ...
container.TryAllImplementations(
(IProcess svc) => svc.ProcessItem(workType),
ex => Console.WriteLine(
" Failed: {0} - {1}.",
ex.GetType(),
ex.Message));