所以我的問題是:什麼是一個最好的方式)總是知道什麼樣的 例外方法可以拋出什麼樣的錯誤,它可以返回,並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中,我可以爲不同的錯誤代碼提供不同的錯誤消息。 –