如何组织几十个相似的 try-catch 块?
How to organize dozens of similar try-catch blocks?
我有外部接口,假设有 20 个类似的方法。每个人都可以扔任何东西。
所以,我有 20 个方法,如下所示:
void Call3Wrapper(int& important_parameter)
{
try
{
external_namespace::IExternal::Call3(important_parameter);
}
catch(external_namespace::Exception& ex)
{
LogIt(ex, "Call3");
throw mynamespace::MyException(ex);
}
catch(std::exception& ex)
{
LogIt(ex, "Call3");
throw mynamespace::MyException(ex);
}
catch(...)
{
LogIt("Unresolved exception", "Call3");
throw mynamespace::MyException("Unresolved exception");
}
}
每个 Call1-Call20 都相同(使用不同参数调用)。
如:
- void Call7Wrapper(std::string& important_parameter)
- void Call12Wrapper(bool& important_parameter, double&
important_parameter2)
...等等
我有很好的函数 LogIt
可以处理所有这些情况,我们自己的类型 MyException
也可以处理所有这些情况。
而且所有这 20 (40, 60) 个函数的主体看起来都很丑陋,因为 90% 的代码都是完全相似的 try-catch 检查。当开发人员需要修复所有相同的东西时,他就会死去...
是否存在一种方法/实践如何组织它不那么丑陋的方式?
类似于构造函数和析构函数中的 lock-unlock-idiom,但对于 try-catch?
我绝对不想用#define CALLS_CATCH_BLOCK(call_name) ...
也许你可以模板化包装器并通过函数对象调用它:
template<typename CALLABLE_T>
void CallWrapper(CALLABLE_T callable, const char* name)
{
try
{
callable();
}
catch(external_namespace::Exception& ex)
{
LogIt(ex, name);
throw mynamespace::MyException(ex);
}
catch(std::exception& ex)
{
LogIt(ex, name);
throw mynamespace::MyException(ex);
}
catch(...)
{
LogIt("Unresolved exception", name);
throw mynamespace::MyException("Unresolved exception");
}
}
然后你可以使用std::bind
创建带参数的可调用对象,例如:
CallWrapper(std::bind(&external_namespace::IExternal::Call3,
std::ref(important_parameter)),
"Call3");
(或 boost::bind
/boost::ref
对于较旧的编译器)
请注意,编译器仍会为每个不同的 CALLABLE_T
类型生成模板实例,但您无需重复代码。
另请注意,这种方式还可以调用和处理类等的成员函数
如果要由 API 接口使用,您可能仍需要创建单独的方法,但在内部调用模板包装器而不是重复异常处理代码。
我有外部接口,假设有 20 个类似的方法。每个人都可以扔任何东西。
所以,我有 20 个方法,如下所示:
void Call3Wrapper(int& important_parameter)
{
try
{
external_namespace::IExternal::Call3(important_parameter);
}
catch(external_namespace::Exception& ex)
{
LogIt(ex, "Call3");
throw mynamespace::MyException(ex);
}
catch(std::exception& ex)
{
LogIt(ex, "Call3");
throw mynamespace::MyException(ex);
}
catch(...)
{
LogIt("Unresolved exception", "Call3");
throw mynamespace::MyException("Unresolved exception");
}
}
每个 Call1-Call20 都相同(使用不同参数调用)。
如:
- void Call7Wrapper(std::string& important_parameter)
- void Call12Wrapper(bool& important_parameter, double& important_parameter2)
...等等
我有很好的函数 LogIt
可以处理所有这些情况,我们自己的类型 MyException
也可以处理所有这些情况。
而且所有这 20 (40, 60) 个函数的主体看起来都很丑陋,因为 90% 的代码都是完全相似的 try-catch 检查。当开发人员需要修复所有相同的东西时,他就会死去...
是否存在一种方法/实践如何组织它不那么丑陋的方式? 类似于构造函数和析构函数中的 lock-unlock-idiom,但对于 try-catch?
我绝对不想用#define CALLS_CATCH_BLOCK(call_name) ...
也许你可以模板化包装器并通过函数对象调用它:
template<typename CALLABLE_T>
void CallWrapper(CALLABLE_T callable, const char* name)
{
try
{
callable();
}
catch(external_namespace::Exception& ex)
{
LogIt(ex, name);
throw mynamespace::MyException(ex);
}
catch(std::exception& ex)
{
LogIt(ex, name);
throw mynamespace::MyException(ex);
}
catch(...)
{
LogIt("Unresolved exception", name);
throw mynamespace::MyException("Unresolved exception");
}
}
然后你可以使用std::bind
创建带参数的可调用对象,例如:
CallWrapper(std::bind(&external_namespace::IExternal::Call3,
std::ref(important_parameter)),
"Call3");
(或 boost::bind
/boost::ref
对于较旧的编译器)
请注意,编译器仍会为每个不同的 CALLABLE_T
类型生成模板实例,但您无需重复代码。
另请注意,这种方式还可以调用和处理类等的成员函数
如果要由 API 接口使用,您可能仍需要创建单独的方法,但在内部调用模板包装器而不是重复异常处理代码。