假设我有一个.NET程序集A,它使用反射来加载程序集B和C(也是.NET)。这两个程序集都实现了许多大型接口(两者都相同)。当在A中调用方法时,它试图使B完成工作。但是,B不可靠,可能会抛出异常。现在A有两种模式,一种是将异常传播给A的调用者,另一种是在更稳定(但性能较差)的C上调用匹配方法。
实现这种场景是否有更好的方法(更少的代码),而不是将所有方法B暴露在所有B接口的大量实现中,现在只围绕每个使用代码的调用,如下所示?程序集B和C对所选的错误处理方法一无所知,因此无法实现逻辑。
public class BErrorWrapper : I1, I2, I3{
...
public int DoSomeWork(int num){
if (FailWithExceptions)
{
try
{
return B.DoSomeWork(num);
}
catch(MyLibException e)
{
return C.DoSomeWOrk(num);
}
}
else
{
return B.DoSomeWork(num);
}
}
...
}
答案 0 :(得分:2)
你可以这样做,它可以节省一些重复:
public class BErrorWrapper : I1, I2, I3{
...
public int DoSomeWork(int num){
try
{
return B.DoSomeWork(num);
}
catch(MyLibException e)
{
if (FailWithExceptions) throw;
return C.DoSomeWOrk(num);
}
}
...
}
答案 1 :(得分:1)
嗯......要保存一些代码,你可以通过委托来包装大多数常见签名,如下所示(注意我只包括核心位以保持清晰 - 但你可以添加你的FailWithExceptions
东西平凡):
static void TryWithFallback<T>(Action<T> primary, Action<T> fallback, T arg)
{
try
{
primary(arg);
}
catch // add your other regular code here...
{
fallback(arg);
}
}
然后您可以通过以下方式重新使用它来实现:
TryWithFallback(b.DoSomeWork, c.DoSomeWork, num);
显然,您可以为相关代码添加一些签名,例如:
static TResult TryWithFallback<T, TResult>(Func<T, TResult> primary, Func<T, TResult> fallback, T arg)
{
try
{
return primary(arg);
}
catch
{
return fallback(arg);
}
}
答案 2 :(得分:1)
我建议你看看使用反射和System.CodeDom来生成代码。我最近有一个类似的问题,当我试图为COM互操作程序集编写一个包装器时,它有一个非常大的接口,有很多方法,签名包含我不想在客户端使用的参数类型,但我可以很容易转换为我在客户端想要的类型。它们也是'ref'参数,这将使客户端代码更加冗长。这些方法有不同数量的参数,我想在客户端公开有意义的名称。
为包装器编写一个基类,该包装器具有A和B实例的成员。编写一个生成派生包装类的代码生成类。然后,代码生成应该迭代包装器应该实现的每个接口的方法,并添加一个方法和方法体,并使用适当的代码在您需要的错误处理构造中调用A和B.生成的用于调用A和B的代码将取决于您调用的方法的签名,但通过迭代生成或调用的方法的参数并不难实现。
我可以发布我的代码,但由于我做的事情略有不同,我认为你最好回到MSDN或其他公共示例。我只能说,我发现这个令人惊讶的直截了当且坚固。
我建议您检查代码生成代码而不是生成的代码,并在构建过程中运行代码生成。