所以我的问题是:什么是一个最好的方式)总是知道什么样的 例外方法可以抛出什么样的错误,它可以返回,并b)不能忘记观察方法的结果错误?
为了解决“一”:
很难在编译时做到这一点。但是你可以在运行时通过反射来完成。请参阅ErrorHandlerFor<T>
类中的静态enumValues
字段。
为了解决“B”,你可以做这样的:
简单:不是一个switch
通话结束后,你准备错误处理程序(以前在case
份)lambda表达式,并把所有的人在ErrorHandlerFor<T>
类中,并将其传递给该函数。这增加了对功能是否继续或中止给予反馈的额外好处。
你也可以认为这是这样的:
假设你想给一些工作的研究员。这项工作可能会以多种方式失败。
传统上,你给这个家伙工作,一直等到它完成,可能有错误。如有必要,您可以处理这些错误。
现在你给这个家伙一些“电话号码”,以便在发生某些错误时调用。如果工作能够继续下去或者需要中止,那么电话的答案甚至可以指导家庭成员。
enum AError
{
AError1,
AError2,
AError3,
AError4,
AError5,
}
delegate bool SingleErrorHandlerDelegate<T>(T error, object someOtherPayload);
interface IHandle<T>
{
bool Handle(T error, object someOtherPayload); // return true if handled;
}
class ErrorHandlerFor<T> : IHandle<T>
{
private Dictionary<T, SingleErrorHandlerDelegate<T>> handlers;
private static T[] enumValues = Enum.GetValues(typeof(T)).Cast<T>().ToArray();
public ErrorHandlerFor(IEnumerable<KeyValuePair<IEnumerable<T>, SingleErrorHandlerDelegate<T>>> handlers)
: this(handlers.SelectMany(h => h.Key.Select(key => new KeyValuePair<T, SingleErrorHandlerDelegate<T>>(key, h.Value))))
{
}
public ErrorHandlerFor(IEnumerable<KeyValuePair<IEnumerable<T>, SingleErrorHandlerDelegate<T>>> handlers, SingleErrorHandlerDelegate<T> fallbackHandler)
: this(handlers.SelectMany(h => h.Key.Select(key => new KeyValuePair<T, SingleErrorHandlerDelegate<T>>(key, h.Value))), fallbackHandler)
{
}
public ErrorHandlerFor(IEnumerable<KeyValuePair<T, SingleErrorHandlerDelegate<T>>> handlers)
{
this.handlers = new Dictionary<T, SingleErrorHandlerDelegate<T>>();
foreach (var handler in handlers)
{
Debug.Assert(handler.Value != null);
this.handlers.Add(handler.Key, handler.Value);
}
checkHandlers();
}
public ErrorHandlerFor(IEnumerable<KeyValuePair<T, SingleErrorHandlerDelegate<T>>> handlers, SingleErrorHandlerDelegate<T> fallbackHandler)
{
this.handlers = new Dictionary<T, SingleErrorHandlerDelegate<T>>();
foreach (var handler in handlers)
{
Debug.Assert(handler.Value != null);
this.handlers.Add(handler.Key, handler.Value);
}
foreach (var enumValue in enumValues)
{
if (this.handlers.ContainsKey(enumValue) == false)
{
this.handlers.Add(enumValue, fallbackHandler);
}
}
checkHandlers();
}
private void checkHandlers()
{
foreach (var enumValue in enumValues)
{
Debug.Assert(handlers.ContainsKey(enumValue));
}
}
public bool Handle(T error, object someOtherPayload)
{
return handlers[error](error: error, someOtherPayload: someOtherPayload);
}
}
class Test
{
public static void test()
{
var handler = new ErrorHandlerFor<AError>(
new[]{
new KeyValuePair<IEnumerable<AError>, SingleErrorHandlerDelegate<AError>>(
new []{AError.AError1, AError.AError2, AError.AError4,},
(AError error, object payload) => { Console.WriteLine(@"handled error 1, 2 or 4!"); return true;}
),
new KeyValuePair<IEnumerable<AError>, SingleErrorHandlerDelegate<AError>>(
new []{AError.AError3, AError.AError5,},
(AError error, object payload) => { Console.WriteLine(@"could not handle error 3 or 5!"); return false;}
),
}
);
var result = Services.foo(handler);
var incompleteHandlerButWithFallbackThatWillPassTheTest = new ErrorHandlerFor<AError>(
new[]{
new KeyValuePair<IEnumerable<AError>, SingleErrorHandlerDelegate<AError>>(
new []{AError.AError1, AError.AError2, AError.AError4,},
(AError error, object payload) => { Console.WriteLine(@"handled error 1, 2 or 4!"); return true;}
),
new KeyValuePair<IEnumerable<AError>, SingleErrorHandlerDelegate<AError>>(
new []{AError.AError5},
(AError error, object payload) => { Console.WriteLine(@"could not handle error 3 or 5!"); return false;}
),
}
// AError.AError3 is not handled! => will go in fallback
, (AError error, object payload) => { Console.WriteLine(@"could not handle error in fallback!"); return false; }
);
var result2 = Services.foo(incompleteHandlerButWithFallbackThatWillPassTheTest);
var incompleteHandlerThatWillBeDetectedUponInstantiation = new ErrorHandlerFor<AError>(
new[]{
new KeyValuePair<IEnumerable<AError>, SingleErrorHandlerDelegate<AError>>(
new []{AError.AError1, AError.AError2, AError.AError4,},
(AError error, object payload) => { Console.WriteLine(@"handled error 1, 2 or 4!"); return true;}
),
new KeyValuePair<IEnumerable<AError>, SingleErrorHandlerDelegate<AError>>(
new []{AError.AError3},
(AError error, object payload) => { Console.WriteLine(@"could not handle error 3 or 5!"); return false;}
),
} // AError.AError5 is not handled! => will trigger the assertion!
);
}
}
class Services
{
public static Result foo(IHandle<AError> errorHandler)
{
Debug.Assert(errorHandler != null);
// raise error...
var myError = AError.AError1;
var handled = errorHandler.Handle(error: myError, someOtherPayload: "hello");
if (!handled)
return new Result();
// maybe proceed
var myOtherError = AError.AError3;
errorHandler.Handle(error: myOtherError, someOtherPayload: 42); //we'll return anyway in this case...
return new Result();
}
public class Result
{
}
}
您可以添加一些自定义或预定义的属性来标记可能的异常,但为什么您需要知道它们? – lavrik
如果我将错误代码转换为异常,它们将是业务异常,并且无论如何我必须将它们捕获到控制器中并转换为错误代码,这些代码稍后将由JavaScript处理程序或服务器响应消耗。而在JavaScript中,我可以为不同的错误代码提供不同的错误消息。 –