1

问题:

我有一些代码失败,因为对象尚未初始化。检测到此错误的解决方案很容易修复。然而,令我惊讶的是,我精心处理的异常处理并没有捕捉到这个异常。这意味着没有记录或处理异常,并且 try catch 块之后的代码从未执行过。try...catch 块在事务之外,所以那里没有问题。

在这种特殊情况下,异常发生在批处理 (RunBaseBatch) 作业中。该作业处理了几个不相关的处理任务。一旦满足异常条件,作业就会终止,因此其他不相关的处理任务永远不会被调用。

有谁知道是否可以在 Dynamics AX 2009 中捕获“对象未初始化”异常?我读过一篇文章说可能无法在 AX 中捕获某些异常,但是,我希望情况并非如此(参考:https ://community.dynamics.com/product/ax/f/33/p/ 16352/23700.aspx#23700)。

代码示例: 这是一些重现问题的简单代码:

server static void main(Args args)
{
    Array   arr;
    ;
    info ("debug: before try...catch");
    try
    {
//        ttsbegin;       // enable/disable to test with transactions
//        arr = new Array(Types::String);     // Enabling this line will prevent the exception
          arr.exists(3);
//        ttscommit;      // enable/disable to test with transactions
    }
    catch (Exception::Internal)  // This exception handler was the Magic Sauce!!
    {
        info ("debug: catch (Exception::Internal)");
    }
    catch (Exception::Error)
    {
        info ("debug: catch (Exception::Error)");
    }
    catch
    {
        info ("debug: catch");
    }
    info ("debug: after try...catch");
}

更新 2013-01-29 我正在等待接受答案,直到更多地查看此问题。谢谢你到目前为止的答案。

我知道我给出的例子很简单。这种类型的错误在已知时很容易修复。防御性编程总是一个好主意。

然而,在现实世界中,出现错误的代码非常复杂。该错误发生在子类的重载方法的几个层次。它发生在特定场景中,当重载方法破坏了超类中成员变量的受保护值时。这就是代码中出现错误的地方,但是,直到超类再次尝试使用成员变量,它才显现出来。该错误在被检测到并被追踪时被立即修复。

防御性地,是的,您可以在每次使用它时检查每个受保护的成员变量,但这确实开始影响性能、代码可读性、实用性等,这就是语言提供异常处理的原因。

这里的问题是如何捕获这些类型的错误以使代码更加健壮和防弹?在大多数开发环境(例如 C、C++、C# 或 Java)中,顶级的 try...catch 可用于捕获、记录和清理所有意外异常。因此代码将能够继续处理其他不相关的任务。AX 在某种程度上仍在继续,因为当这个错误发生时,整个系统并没有停止。但是,由于 AX/X++ 中的缺陷,此作业中 catch 之后的代码没有执行。

我正在寻找一种创新的解决方案或解决方法(如果存在)来捕获“对象未初始化”异常(实际上是所有异常)并继续处理。

4

3 回答 3

3

你不能在传统意义上“抓住”它,但你可以避免它发生。在运行任何东西之前简单地测试对象是否存在:

if(object)
{
    // Exists; Execute statements with object here
}
else 
{
    // Doesn't exist
}

这是有效的,因为如果对象未初始化,它将被转换为 null。(空 == 0)== 假

如果对象已初始化,它将具有除 null 之外的其他值。(!Null != 0) == 真

希望有帮助!

于 2013-01-25T20:19:12.767 回答
2

详细说明一下,如您链接到的帖子中所述,您无法捕获 Object Not Initialized 错误。但是,您可以通过在尝试针对您无法控制的变量运行函数之前添加一个简单的检查来“修复”代码(例如,如果您请求 Array 类型作为函数的参数并且您希望函数从类外调用)。

    try
    {
          if (arr)
              arr.exists(3);
    }

如果对象尚未实例化,if(arr) 语句足以跳过处理,有效地绕过错误。但是,这显然不会将错误进一步推向链条。如果你真的想要,你可以让它抛出一个可以被捕获的不同错误,但显然这不太理想。

在这种情况下,由于 RunBaseBatch 类可能不是您想要修改的东西,因此在调用问题方法之前确保正确定义导致问题的对象并在测试中发现这些错误可能会更好。

于 2013-01-24T13:58:26.463 回答
2

You can, but you shouldn't. A behavior like this is almost certainly a bad design of your code, that will inevitably end in more problems in the future.

You need to make your code defensive to this case, making sure the object is instanciated before using it. Otherwise, you're using the catch code to an expected behavior, wich makes no sense.

EDIT 2013/02/18

In complex scenarios like what you're describing, it's usually very hard to get a solution fully controlled. In AX, try..catch statement is quite simplified and in a very large range of situations is not really needed (unlike Java, C#, ... where is always recommended).

This simplification is nice in almost all situations of AX development, as you don't need to waste time on exception handling. Just let them raise, and the InfoLog will handle them on a simple and reliable way.

The big problem comes where you really need this control... when there is not really a way of force it. I'm not sure if this is really an standard issue or it's espected by the product team to work that way, but this cases are always giving troubles in AX. When you need to catch some specific issue you have to be very creative and deffensive to prevent the exception as catching it will become even more creative...

Hope this helps :)

于 2013-01-28T11:01:03.230 回答