How to cleanly throw an exception from LispFunction
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
Hi,
When defining new LISP function with .NET, I think it's necessary to first check for the argument validity (number and type) and I am convinced the evaluation must stop in case of invalid inputs (as the built-in LISP function work).
Fot this, I use some classes which inherit from System.Exception:
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
namespace LispFunctionSample
{
/// <summary>
/// Base exception type for LISP exceptions.
/// </summary>
class LispException : System.Exception
{
/// <summary>
/// Creates a new instance of LispException.
/// </summary>
/// <param name="msg">The message to be displayed when LispException is thrown.</param>
public LispException(string msg)
: base(msg) { }
}
/// <summary>
/// Exception to be used if the LISP function is called with too few arguments.
/// </summary>
class TooFewArgsException : LispException
{
/// <summary>
/// Creates a new instance of TooFewArgsException.
/// </summary>
public TooFewArgsException()
: base("too few arguments") { }
}
/// <summary>
/// Exception to be used if the LISP function is called with too many arguments.
/// </summary>
class TooManyArgsException : LispException
{
/// <summary>
/// Creates a new instance of TooManyArgsException.
/// </summary>
public TooManyArgsException()
: base("too many arguments") { }
}
/// <summary>
/// Exception to be used if the LISP function is called with an incorrect argument type.
/// </summary>
class ArgumentTypeException : LispException
{
/// <summary>
/// Creates a new instance of ArgumentTypeException
/// </summary>
/// <param name="msg">The string to be displayed in the message
/// (fixnump, numberp stringp, listp, lentityp, lselsetp).</param>
/// <param name="tv">The TypedValue representing the incorrect argument.</param>
public ArgumentTypeException(string msg, TypedValue tv)
: base(string.Format(
"bad argument type: {0}: {1}",
msg,
tv.TypeCode == (int)LispDataType.Nil ?
"nil" :
tv.TypeCode == (int)LispDataType.Text ?
"\"" + tv.Value + "\"" :
tv.Value))
{ }
}
}
These exceptions may be thrown from the LispFunction code, catched to display a message and re-raised to stop the LISP evaluation.
Example:
[LispFunction("acos")]
public double Acos(ResultBuffer resbuf)
{
try
{
if (resbuf == null)
throw new TooFewArgsException();
TypedValue[] args = resbuf.AsArray();
if (args.Length > 1)
throw new TooManyArgsException();
int code = args[0].TypeCode;
if (code != (int)LispDataType.Int16 && code != (int)LispDataType.Int32 && code != (int)LispDataType.Double)
throw new ArgumentTypeException("numberp", args[0]);
double value = Convert.ToDouble(args[0].Value);
if (value < -1.0 || value > 1.0)
throw new LispException("the value must be between -1.0 and 1.0 inclusive");
return Math.Acos(value);
}
catch (System.Exception ex)
{
AcAp.DocumentManager.MdiActiveDocument.Editor.WriteMessage("\n; error: " + ex.Message + "\n");
throw;
}
}
This works quite fine except the message in the command line is followed by an eInvalidAdsName stack trace and, in the Visual LISP console, the message is: "; error: ADS request error".
So, is there a way to avoid the eInvalidAdsName stack trace in the command line and have the thrown exception message in the Visual LISP console so that it mimics closer the built-in functions?
Thanks in advance.