Catching Ironpython Exception in C#

2020-06-17 06:25发布

问题:

I'm embedding IronPython 2.0 in C#. In IronPython, I defined my own exception with:

def foobarException(Exception):
    pass 

and raise it somewhere with:

raise foobarException( "This is the Exception Message" )

Now in C#, I have:

try
{
   callIronPython();
}
catch (Exception e)
{
   // How can I determine the name (foobarException) of the Exception
   // that is thrown from IronPython?   
   // With e.Message, I get "This is the Exception Message"
}

回答1:

When you catch an IronPython exception from C#, you can use the Python engine to format the traceback:

catch (Exception e)
{
    ExceptionOperations eo = _engine.GetService<ExceptionOperations>(); 
    string error = eo.FormatException(e); 
    Console.WriteLine(error);
}

You can pull the exception name out of the traceback. Otherwise, you will have to call into the IronPython hosting API to retrieve information directly from the exception instance. engine.Operations has useful methods for these kinds of interactions.



回答2:

The way IronPython maps .NET exceptions to Python ones isn't always straightforward; a lot of exceptions are reported as SystemError (although if you import the .NET exception type you can specify that in the except clause). You can get the Python type of the exception using

type(e).__name__

If you want the .NET exception type, make sure you have import clr in the module. It makes .NET attributes available on objects, like the ToUpper() method on strings. Then you can access the .NET exception using the .clsException attribute:

import clr
try:
    1/0
except Exception, e:
    print type(e).__name__
    print type(e.clsException).__name__

prints:

ZeroDivisionError      # the python exception
DivideByZeroException  # the corresponding .NET exception

An example of catching the specific .NET exception you want:

from System import DivideByZeroException
try:
    1/0
except DivideByZeroException:
    print 'caught'


回答3:

My final solution was:

I have a result class in C# which is passed to my ironpython code. In Ironpython I fill the result class with all my computed values. To this class I just added a member variable IronPythonExceptionName. Now I just have a simple try in IronPython:

try: 
    complicatedIronPythonFunction()
except Exception, inst:
    result.IronPythonExceptionName = inst.__class__.__name__
    raise inst


回答4:

Assuming that you compiled your python code with the .NET equivalent compiler you would have a static type which is just that exception. If this exception is public (exported type) then you reference the assembly that contains your python code in your project and dig up the type foobarException in some python namespace. That way C# will be able to type match that exception. This is the only way you can do that properly.