我试图做我的C#代码错误的沟通和恢复,而无需使用异常。 举一个例子,假设有一个函数功能A,其可通过函数功能B或函数功能C或其它功能来调用。 FUNC A必须设计保持重用的初衷。 (此应用程序中都有新的功能会越来越添加一段时间的演变库)
如果函数功能A不能够做什么是应该做的,它返回一个int,其中任何非零值表示失败。 我也想沟通失败的原因。 调用者函数可以使用多种方式这样的信息:
- 它可以显示错误信息给用户,
- 它可以显示自己的错误消息的更多有关它的上下文
- 它本身可以返回指示未能进一步祖先呼叫者函数int值。
- 它可能会尝试从错误中恢复,使用一些智能算法。
假设地,在其上的其他功能依赖于任何功能,可能需要多件事情传达给它的调用者函数来采取适当的行动,包括状态代码,错误消息,并且其它变量指示数据的状态。 回到一切作为分隔字符串可能不允许调用函数在不解析字符串(这将导致其自身的问题,不建议使用)获取信息。
唯一的其他方式是返回包含成员变量的对象对所有所需的信息。 这可能导致过多的“状态”对象,每个功能都需要有其状态的对象。
我想了解这个要求可以在最优雅的方式来设计。 需要注意的是,在编码的时候,Func键A可能不知道调用函数是否有智能从错误或不恢复,所以我不想抛出异常。 另外,我希望看到这样的设计是否可行(和优雅的同时),而不使用异常。
如果唯一的办法就是使用数据对象的每个功能进行沟通,然后是它的专业库的编写方式。 能有一个通用的数据对象? 注意新的功能可以在将来会增加,这可能有不同的状态变量,或支持他们的错误的信息。
还要注意,由于函数的返回值是一个“国家”的对象,它应该返回的实际数据可能需要作为ref或out参数传递。
是否有这样的设计模式?
我已阅读张贴了这个问题之前,下面的文章:
http://blogs.msdn.com/b/ricom/archive/2003/12/19/44697.aspx
不要试图损害性能/ catch块时异常不抛出?
错误处理无异常
我看了很多其他文章,也是这样的,建议不要使用码流控制的异常,以及它们是可恢复的错误。 此外,抛出异常有自己的成本。 此外,如果调用函数要由每个调用的函数抛出的异常恢复,它必须围绕每个函数调用与try catch块,作为一种通用的try catch块将不允许“继续”从下一行错误行的。
编辑:
有几个具体的问题:我需要写这将同步2个不同的数据库的应用程序:一个是proprietory数据库,另一个是SQL Server数据库。 我想在一个单独的层来封装可重复使用的功能。
该功能是这样的:proprietory应用程序可以有多个数据库。 需要从每个数据库的一些信息被推向一个常见的SQL Server数据库。 该proprietory应用程序的数据库,可以读取,只有当应用程序的GUI是开放的,它只能通过XML读取。
该算法是这样的:
- 阅读Proprietory应用程序打开数据库列表
- 对于每个数据库,启动同步过程。
- 检查用户是否当前登录,在这个数据库有同步权限。 (注:每个数据库可以使用不同的用户ID被打开)。
- 从这个数据库中读取数据。
- 将数据传输到SQL Server
- 继续执行下一个数据库。
在开发这个应用程序,我会写一些可重复使用的功能,如ReadUserPermission,ReadListOfDatabases等。
在这种情况下,如果ReadUserPermission认定,许可不存在,则调用者应该记录这一点,并继续下打开数据库。 如果ReadListOfDatabases是无法建立与Proprietory应用程序的连接,调用者应该自动启动应用程序,等等。
那么,哪些错误情况应通知应例外和使用的返回码?
请注意,可重复使用的功能,可以在其他项目中,通常是主叫可以有不同的错误恢复的要求或能力被使用,从而使必须牢记。
编辑:
对于那些崇尚例外,我问他们:如果Func键A调用函数功能B,C,d,E,F,G和Func键乙抛出一些异常错误的情况,但Func键A可以从这个错误中恢复,并希望继续执行即调用函数功能B,C,d,......,请问异常处理允许这样做“优雅”其他人呢? 唯一的解决方法是将一个try catch块内换到每个B,C,d,调用的...,让剩下的语句得到执行。
也请仔细阅读这些2个评论:
https://stackoverflow.com/a/1279137/1113579
https://stackoverflow.com/a/1272547/1113579
请注意 ,我不反对使用异常,如果错误恢复和剩余的代码执行,可以优雅 ,不影响性能来实现的。 此外,轻微的性能影响不是一个问题,但我更喜欢的设计应具有可扩展性和优雅。
编辑:
好吧,基于“Zdeslav Vojkovic”意见,我现在想使用异常。
如果我使用异常,可以给予一定的使用情况下,当不使用异常,而是使用返回代码? 注意:我说的是返回代码 ,而不是其功能应该将数据返回。 有没有使用返回代码表示成功/失败,或者没有用例的任何使用情况下? 这将帮助我更好地理解。
例外的一个用例是我从“Zdeslav Vojkovic”理解是,当被调用函数要强制通知的一些情况主叫功能和中断调用程序执行。 在没有异常,调用者可能会或可能不会选择检查返回代码。 但在例外的情况下,调用函数必定处理异常, 如果它想继续执行 。
编辑:
我还有另外一个有趣的想法。 所有被调用函数要支持来电显示功能,从错误中恢复可以提高事件,并检查事件数据的事件已处理后,再决定扔还是不扔异常的想法。 错误代码不会在所有使用。 异常将被用于不可恢复的错误。 基本上,当被调用函数是无法做到的合同怎么说,它要求在任何可用的事件处理程序的形式“帮助”。 不过,如果它不能履行合同的,它抛出一个异常。 其优点是,抛出异常的额外开销被降低,而当调用函数或任何其调用函数无法从错误中恢复例外只抛出。
假设如果调用函数并不想处理错误,而是调用者的调用函数要处理错误,自定义事件调度程序将确保事件处理程序被称为事件注册的顺序相反,即最近注册的事件处理程序应该先于其它注册的事件处理程序被调用,如果此事件处理程序能够解决错误,随后的事件处理程序不是在所有调用。 在另一方面,如果最新的事件处理程序不能纠正错误,事件链将传播到下一个处理。
请给这种方法的反馈。
如何共同FunctionResult
你作为使用对象out
所有你的方法,你不希望在抛出异常PARAM?
public class FuncResultInfo
{
public bool ExecutionSuccess { get; set; }
public string ErrorCode { get; set; }
public ErrorEnum Error { get; set; }
public string CustomErrorMessage { get; set; }
public FuncResultInfo()
{
this.ExecutionSuccess = true;
}
public enum ErrorEnum
{
ErrorFoo,
ErrorBar,
}
}
public static class Factory
{
public static int GetNewestItemId(out FuncResultInfo funcResInfo)
{
var i = 0;
funcResInfo = new FuncResultInfo();
if (true) // whatever you are doing to decide if the function fails
{
funcResInfo.Error = FuncResultInfo.ErrorEnum.ErrorFoo;
funcResInfo.ErrorCode = "234";
funcResInfo.CustomErrorMessage = "Er mah gawds, it done blewed up!";
}
else
{
i = 5; // whatever.
}
return i;
}
}
确保您的所有功能没有异常,可以失败有out
参数有关FuncResultInfo
“是它的专业库的编写方式?”
不,专业图书馆通过使用错误处理异常写 - 我不知道是否有使用你的建议的方法模式,但我认为这是一种反模式(在.NET)。 毕竟,.NET本身就是一个专业的框架,它使用了异常 。 此外,.NET开发人员用来例外。 你认为你的库是真的那么特别,迫使用户学习的错误处理方式完全不同?
你刚才所做的是重塑COM错误处理。 如果这是你想要做什么,然后检查这和ISupportErrorInfo
接口的一些想法。
你为什么要这么做? 我敢打赌,这是一个性能“优化”。
的关于异常处理性能问题的恐惧几乎总是过早的优化。 您将创建一个尴尬的API,其中每一个返回值必须通过REF /输出参数进行处理,并且会伤害你的lib的每个用户,正好解决了它可能根本不存在的所有问题。
“FUNC A可能不知道调用函数是否有智能从错误或不恢复,所以我不想抛出异常”
所以你要确保调用者默默允许FuncA的搞乱系统不变和来电者只是去愉快地? 这将只是使它更难调试看似不可能的错误,这发生在另一个函数以后缘于此。
还有的情况下才有意义,以避免异常,但应该有一个很好的理由。 例外的是好主意。
编辑:我看到你还说你“看了很多其他文章,也是这样的,建议不要使用码流控制异常”。 这是正确的,在.NET异常不是为代码流,但用于错误处理。
你问:
如果Func键A调用函数功能B,C,d,E,F,它有封装与尝试捕捉每一个呼叫,因为它可以从错误中恢复,否则将仍然喜欢执行剩余的函数调用,那么是不是这么多的尝试catch语句尴尬
没有比其他多。 你快把你可以从功能于一身的同样的方式简单处理返回的所有错误,一个错误,但你通常不能。
试想,如果你需要单独处理每一个功能 - 最糟糕的情况和代码通常不是这样写的是:
Result x, y;
try {
x = Function1();
}
catch(SomeException e) {
// handle error
}
try {
y = Function2();
}
catch(SomeOtherException e) {
// handle error
}
反对:
int error;
Result x, y;
error = Function1(out x);
if(error != SOME_KNOWN_ISSUE) {
// handle error
}
error = Function2(out y);
if(error != SOME_KNOWN_ISSUE) {
// handle error
}
没有大的差别。 请不要告诉我,你会不会检查错误代码。 但是,如果你决定忽略所有的错误(一个可怕的想法),那么例外是简单的:
try {
var x = Function1();
var y = Function2();
var z = Function3();
}
catch Exception() { you still can see the message here and possibly rethrow }
VS
Result1 r1;
Function1(out r1);
Result2 r2;
Function2(out r2);
Result3 r3;
Function3(out r3);
// and here you still don't know whether there was an error
你能否解释你是什么意思“我需要预见性关于时间限制”?
在一些系统级软件或实时的东西,你不能与异常处理堆栈展开,因为你不能保证时间,而且可能侵犯您的时序要求。 但是,垃圾收集在这方面差得很远,这是从来没有在.NET中的情况。
此外,当你说“在.NET中我总是会使用错误处理的例外”,你能解释一下怎样还是怎样,你定义为一个错误条件? 是可恢复的情况出错或不是一个错误? -
@shambulater已经给在评论一个很好的例子。 在FileStream
,丢失的文件是不可恢复的,它会抛出。 在客户端FileStream
它可能是可恢复的或不依赖于上下文。 有些客户会忽视它,有些人会退出应用程序,有些人会包装在另一个异常,让别人上游来决定。
你什么时候不使用异常?
在这种情况下我也不会返回错误代码。
我广泛使用FunctionResult方法在MS接入和它奇妙的作品。 我认为这是比错误处理好得多。 一开始,每个错误消息是应用特定的,并且不是通常的脱靶默认的错误消息。 如果错误向上传播的功能的呼叫列表,该错误消息可菊花链接在一起。 这最后的错误消息看起来像一个调用堆栈,但清洁如[无法读取驱动器F :,的照片无法读取文件,驱动器未就绪。 怪人,我刚才发现,一些驱动器可以安装,但没有准备好。 我不能有单位的错误,因为我不知道怎么会发生这样的错误检测(指SD卡读卡器为空)。 然而,即使没有这个错误的先验知识,我可以写处理它优雅的应用程序。
我的方法是调用一个方法被编写为返回一个布尔值的函数的类。 返回值设置为True在函数的最后一行,所以如果该函数的最后一行之前退出,这是在默认情况下是不成功的。 我的代码,调用函数看起来像如果getphotos(folderID),然后......做一些事情..否则报错。 类模块内是一个模块级错误变量(力量MEM)和其经由吸气读取,所以类具有保持该错误消息的.EM属性。 我也有一个注释变量,它有时被用于这样的错误消息,例如,如果该文件夹是空的,看起来照片的代码工作,但没有返回任何照片。 这不会是一个错误,但它的东西,我可能想传达给调用程序。 如果有错误,用户会收到一条错误消息,并且调用程序将退出。 相反,如果有一个CMT,如“无照片”,那么我会技巧试图读取例如照片的元数据。 如何Zdeslav Vojkovic处理这样的例外subtlies?
我移动到C#,因此找到这个线程。 我想知道为什么函数调用失败(我与数据库和归档系统所有的时间互动,所以我很难掩盖我的项目在单元测试)的确定性。 我确实与Zdeslav Vojkovic同意关于使用例外情况他们采用的是标准,但不会在我自己的代码来这样做。 我要寻找一个干净的设计模式,它可以让我在被调用函数中的参数进行验证,并告知来电者,如果参数是不正确的。