我目前正在开发一个解决方案,并以一种强大的方式实现策略/提供者模式。因此,该解决方案公开了许多接口,并包含这些接口的默认实现,可以通过DI类型方法替换。
如果主机应用程序使用了许多这些接口,它希望处理可能发生的某些异常,例如IDataRetriever
接口有一个方法SomeDataType GetData(int timeout);
,并且主机可以处理一些自定义异常,例如DataRetrievalTimeoutException
或NetworkConnectionException
。
我的问题是,标记接口类的最佳方法是什么,当开发人员实现它时,他们会知道应该抛出某些异常并由主机处理?
目前我刚刚将xml标签添加到方法xml注释中 - 这是否足够?
答案 0 :(得分:12)
XML标签(以及您想要编写的任何其他文档)基本上是您目前在“vanilla”.NET中最接近的。
您可能希望查看Code Contracts,它允许您使用合同注释您的界面,其中包括例外,先决条件等。
答案 1 :(得分:2)
你不能在界面中。你可以在基类。
public interface IFoo
{
/// <summary>
/// Lol
/// </summary>
/// <exception cref="FubarException">Thrown when <paramref name="lol">
/// is <c>null</c></exception>
/// <remarks>Implementors, pretty please throw FE on lol
/// being null kthx</remarks>
void Bar(object lol);
}
VS
public abstract BaseFoo
{
/// <summary>
/// Lol
/// </summary>
/// <exception cref="FubarException">Thrown when <paramref name="lol">
/// is <c>null</c></exception>
public void Bar(object lol)
{
if(lol == null)
throw new FubarException();
InnerBar(lol);
}
/// <summary>
/// Handles execution of <see cref="Bar" />.
/// </summary>
/// <remarks><paramref name="lol"> is guaranteed non-<c>null</c>.</remarks>
protected abstract void InnerBar(object lol);
}
答案 2 :(得分:2)
我建议在接口中定义异常类,并指定除非CPU处于激烈状态或其他如此剧烈的情况下,否则不应允许任何不从这些异常派生的异常转义(即便如此,它可能不是有一个明确定义的IWoozle.SystemCorruptionException
的坏主意,以便如果一个Pokemon处理程序只是捕获,记录并抛出异常,日志将反映出至少有人认为异常是重要的。)
我认为微软的建议是避免定义自定义异常类型是不幸的,因为这意味着没有干净的方法可以区分IEnumerator<T>.MoveNext()
是否抛出InvalidOperationException
,因为在枚举期间底层集合已被更改,或者IEnumerator<T>.MoveNext()
的内部处理是否遇到InvalidOperationException
并简单地让它冒泡到调用者。如果相反,IEnumerator<T>.MoveNext()
在前一种情况下投了IEnumerator.InvalidatedEnumeratorException
,则转义的任何InvalidOperationException
都必须代表后一种情况。
答案 3 :(得分:1)
这不应该由任何类实现接口吗?
例如,如果我使用您的接口并使用GetData方法实现我自己的类,我可以从任何地方“获取”数据。假设它是一个Web服务,那么可以抛出的异常类型可能与我从本地文件系统“获取”数据时的异常类型不同。
因此,在我的实现中,我将实现(并记录)特定于implmentation的那些异常,以便使用该实现的任何代码都可以处理它们。处理这些异常的方式可能非常具体,例如我在网络应用程序中使用它们而不是桌面应用程序。
答案 4 :(得分:0)
我认为提供此信息的最佳方式是在为每个界面提供的XML文档中。在那里,您可以指定方法抛出的异常,以便主机可以处理该错误。
答案 5 :(得分:0)
如果您不能支持通用基类,另一种策略是扩展方法实现。
public static void ThisMethodShouldThrow(this Iinterface obj)
{
if(obj.ConditionToThrowIsMet) throw new...
}
这样可以让您不需要继承链。