多次实施尝试
我正在开发一个解决方案,该解决方案将连接到各种服务器以读取数据并执行操作。有许多变量使可靠通信变得复杂,例如防火墙、停止/失败的服务、身份验证差异和各种软件配置。我可以使用一些方法来解决这些问题,尽管在执行时尚不知道哪种方法会成功。
我的目标是创建一个可用于执行操作的接口和实现。第一个方法调用将是适用于大多数设备的最快实现,然后是可以处理前面列出的问题的其他调用。
在完美的世界中,该过程将被编写为快速识别哪种方法会成功,但在我的测试中,花费的处理时间与简单捕获异常一样多。虽然性能始终是一个考虑因素,但最终成功完成任务更为重要。
下面是我创建的一个示例,它演示了迭代实现列表的最坏情况场景。虽然这对于一种方法效果很好,但当用于 20 种或更多不同的操作时,它不遵循 DRY 原则。一种可能的解决方案是 Unity 和 Interception,但我发现调用处理程序中的调用方法使用已解析的实现,而不是可能的实现列表。除非我错过了什么,否则这似乎不是一个选择。另外,我需要对多个接口遵循此模式,因此最好创建一个可以迭代实现列表的通用处理程序。
任何有关如何完成此任务的建议将不胜感激!
接口
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;
}
}
}
I am developing a solution which will connect to a wide variety of servers to read data and perform operations. There are many variables which complicate reliable communications such as firewalls, stopped/failed services, authentication differences, and various software configurations. There are methods I can use to work around these issues, though at the time of execution it is not known which will prove successful.
My goal is to create an interface and implementations which can be used to perform operations. The first method call will be to the fastest implementation which works for the majority of devices followed by other calls which can deal with the issues listed earlier.
In a perfect world the process would be written to quickly identify which method would be successful, but in my tests that took as much processing time as simply catching an exception. While performance is always a consideration, in the end it is more important that the task completes successfully.
Below is an example I created which demonstrates a worst case scenario iterating over a list of implementations. While this works well for one method, it doesn't follow the DRY principle when used in 20 or more different operations. One possible solution is Unity and Interception but I found that the invoke method in the call handler uses a resolved implementation, not a list of possible implementations. Unless I am missing something, that doesn't appear to be an option. Also, I will need to follow this pattern for several interfaces, so it would be nice to create a generic handler which can iterate over a list of implementations.
Any advice on how to complete this task would be appreciated!
Interface
public interface IProcess
{
int ProcessItem(string workType);
}
Implementations
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;
}
}
Special Implementation loops through the other implementations until one succeeds without exception
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;
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您可以将处理操作实现为通用扩展方法,您传递一个对单个项目进行处理的方法:
现在您已经分解出项目的实际类型以及用于处理的方法。唯一“固定”的是泛型方法的结果类型,它是一个整数。
对于您当前的示例,您可以这样称呼它:
You could implement the processing operation as a generic extension method that you pass a method that does the processing for a single item:
Now you have factored out the actual type of the item and what method you use for processing. The only thing "fixed" is the result type of the generic method which is an integer.
For your current example you could call it like this then:
您可以在第二个界面中使用 TryParse 模式:
You could use the TryParse pattern in a second interface:
如果您想要非常简单和“通用”的东西,这里有一个类似于@BrokenGlass 创建的解决方案。
由于我看到了 Unity 标记,因此您可以使用服务接口在容器上使用
ResolveAll()
来获取所有实现。将此代码与此代码相结合,您可以在 IUnityContainer 上执行类似扩展方法的操作:以下是如何使用它:
Here's a solution similar to the one created by @BrokenGlass if you want something very simple and "generic."
Since I see a Unity tag, you could use
ResolveAll<TService>()
on your container using your service interface to get all implementations. Combining that with this code, you could do something like an extension method onIUnityContainer
:Here's how using it could work: