我即将使用COM将使用C#编写的服务公开给传统的C ++应用程序。向非托管客户端报告错误的最佳方法是什么?抛出异常或只返回错误值?
谢谢, 斯特凡诺
答案 0 :(得分:10)
你应该抛出异常。框架将异常映射到HRESULTS,而HRESULT是将错误返回给COM客户端的标准方法,因此这是可行的方法。
每个Exception类型都有一个HResult属性。当从COM客户端调用的托管代码抛出异常时,运行时将HResult传递给COM客户端。如果需要特定于应用程序的HRESULT代码,可以创建自己的自定义异常类型并设置Exception.HResult属性。
需要注意的一点是,当向COM客户端抛出异常时,调用堆栈信息将丢失。因此,在传播到COM客户端之前记录异常是个好主意。
我有时使用的一种技术如下:为COM客户端显式实现一个ComVisible接口,用于记录和重新抛出异常。 COM客户端使用ComVisible接口在传播异常之前记录异常。 .NET客户端使用具体类,并期望自己安排异常处理。编写时有点啰嗦,但在您随后进行故障排除时可能会有所帮助。
此方法的另一个优点是,您可以根据COM客户端的COM限制量身定制API,并为标准.NET客户端提供更标准的API。例如,COM客户端仅限于通过引用传递数组,而不支持通过引用传递.NET客户端。
示例:
[
ComVisible(true),
GuidAttribute("..."),
Description("...")
]
public interface IMyComVisibleClass
{
// Text from the Description attribute will be exported to the COM type library.
[Description("...")]
MyResult MyMethod(...);
[Description("...")]
MyOtherResult MyArrayMethod([In] ref int[] ids,...);
}
...
[
ComVisible(true),
GuidAttribute("..."),
ProgId("..."),
ClassInterface(ClassInterfaceType.None),
Description("...")
]
public class MyComVisibleClass : IMyComVisibleClass
{
public MyResult MyMethod(...)
{
... implementation without exception handling ...
}
public MyOtherResult MyArrayMethod(int[] ids,...)
{
... input parameter does not use ref keyword for .NET clients ...
... implementation without exception handling ...
}
MyResult IMyComVisibleClass.MyMethod(...)
{
// intended for COM clients only
try
{
return this.MyMethod(...);
}
catch(Exception ex)
{
... log exception ...
throw; // Optionally wrap in a custom exception type
}
}
MyOtherResult IMyComVisibleClass.MyArrayMethod(ref int[] ids, ...)
{
// intended for COM clients only
try
{
// Array is passed without ref keyword
return this.MyArrayMethod(ids, ...);
}
catch(Exception ex)
{
... log exception ...
throw; // Optionally wrap in a custom exception type
}
}
}
答案 1 :(得分:3)
如果您的COM应用程序在调用C#服务时支持IErrorInfo接口,并且它是一个完全内部项目,那么抛出异常可能是最好的选择,因为它捕获了大部分信息。但是,COM传统上依靠人力资源结果来传达状态结果,如果要将服务发布到其他来源可能会更好。
编辑:我更喜欢Joe的回答。
答案 2 :(得分:3)
我同意其他人的意见,如果不亲密地了解你的项目,这不是一个“是或否”的答案。
这取决于许多因素,例如:
Here's a good blog post that discusses a number of subtle points about exception processing.
作者建议采用以下两种方法之一:
或者:
或:
就个人而言,我认为您应该避免将C#服务与C ++应用程序紧密耦合。换句话说,编写C#服务,以便理论上可以被任何消费者使用。同样,应该编写C ++代码,使其不依赖于C#服务的内部工作,因此对异常(或错误代码)的更改或添加不会破坏使用者。
答案 3 :(得分:1)
我认为这取决于遗留应用程序的反应方式。如果它理解错误返回值,那么请使用该方法。如果没有,那么你将不得不抛出异常并希望它适当地处理它们。
另外,如果它是一个错误的引用(例如null引用)或其他严重错误,我总是会抛出异常。但是,对于消费者无法事先检查的事情(例如,空的搜索不应该抛出异常),应该避免例外情况。
答案 4 :(得分:1)
最好判断您是使用例外还是返回值将是您。 “抛出异常”在几个方面超过了“回归价值”。但在某些情况下,返回值就足够了。