Author Topic: AutoCAD.NET | Handling *Exceptions  (Read 21650 times)

0 Members and 1 Guest are viewing this topic.

BlackBox

  • King Gator
  • Posts: 3770
AutoCAD.NET | Handling *Exceptions
« on: April 16, 2012, 12:33:02 PM »
I'm trying to ensure that I am employing a sort of best practices with regard to handling *Exceptions for CommandMethods, and LispFunctions alike.

One recent example came up when I was coding a snippet that incorporates System.IO.Directory.GetParent() Method.

Rather than using If statements to test for valid criteria, I attempted to Catch ArgumentNullException, and ArgumentException, in addition to my normal Autodesk.AutoCAD.Runtime.Exception, yet each instance of my intentionally providing an argument that I thought would trigger one of these GetParent() Method Exceptions resulted in a Fatal Error, rather than hitting the applicable Catch statement.

Any suggestions, or advise would be most helpful.


Pseudo (non-production) code:

Code - C#: [Select]
  1.             try
  2.             {
  3.                 if (args == null)
  4.                 {
  5.                     ed.WriteMessage("\n; error: too few arguments ");
  6.                     return null;
  7.                 }
  8.  
  9.                 Array myArgs = args.AsArray;
  10.                 int i = myArgs.Length;
  11.  
  12.                 if (i > 1)
  13.                 {
  14.                     ed.WriteMessage("\n; error: too many arguments ");
  15.                     return null;
  16.                 }
  17.  
  18.                 if (myArgs(0).TypeCode != LispDataType.Text)
  19.                 {
  20.                     return null;
  21.                 }
  22.  
  23.                 string filePath = ((TypedValue)myArgs.GetValue(0)).Value;
  24.                 DirectoryInfo pathInfo = Directory.GetParent(filePath);
  25.  
  26.                 if (pathInfo.Exists & Directory.Exists(filePath))
  27.                 {
  28.                     return pathInfo.FullName;
  29.                 }
  30.  
  31.             }
  32.             catch (ArgumentNullException ex)
  33.             {
  34.                 ed.WriteMessage("\n; error: " + ex.Message + "\n ");
  35.                 return null;
  36.  
  37.             }
  38.             catch (ArgumentException ex)
  39.             {
  40.                 ed.WriteMessage("\n; error: " + ex.Message + "\n ");
  41.                 return null;
  42.  
  43.             }
  44.             catch (Autodesk.AutoCAD.Runtime.Exception ex)
  45.             {
  46.                 ed.WriteMessage("\n; error: " + ex.Message + "\n ");
  47.                 return null;
  48.  
  49.             }
  50.  
"How we think determines what we do, and what we do determines what we get."

huiz

  • Swamp Rat
  • Posts: 917
  • Certified Prof C3D
Re: AutoCAD.NET | Handling *Exceptions
« Reply #1 on: April 16, 2012, 01:15:20 PM »
The only way to escape from a fatal error is to catch the error as a system.exception. While debugging you can probably see what kind of exception it is.
The conclusion is justified that the initialization of the development of critical subsystem optimizes the probability of success to the development of the technical behavior over a given period.

BlackBox

  • King Gator
  • Posts: 3770
Re: AutoCAD.NET | Handling *Exceptions
« Reply #2 on: April 16, 2012, 01:21:28 PM »
Thanks for the response, Huiz.

Perhaps I am not understanding how the Method specific Exceptions work then... This is the first time I am attempting to incorporate them. I usually just use If statements.

If the GetParent() Method has an ArgumentNullException, and I supply a Null argument to the Method, how/why does this trigger a System.Exception, rather than ArgumentNullException  :? ?

Is there anything wrong with the order (top to bottom) of the Exceptions I am attempting to Catch? I know ArgumentNullException needs to be placed above ArgumentException, for instance.
"How we think determines what we do, and what we do determines what we get."

exmachina

  • Guest
Re: AutoCAD.NET | Handling *Exceptions
« Reply #3 on: April 16, 2012, 01:39:34 PM »
IF you only need to display a message, just use System.Excepcion

Code - C#: [Select]
  1. string path = null;
  2. try {
  3.     Directory.GetParent(path);
  4. } catch (System.Exception ex) {
  5.   MessageBox.Show(ex.Message);
  6. }

If you need to manipulate some specific exceptions you can use something like this (use System.Exception in the last "catch" or just an empty catch block)

Code - C#: [Select]
  1. try {
  2.     Directory.GetParent(path);
  3. } catch (DirectoryNotFoundException ex1) {
  4.     //anything
  5. } catch (ArgumentException ex2) {
  6.     //anything
  7. } catch (System.Exception ex) {
  8.   MessageBox.Show("unhandled exception: " +ex.Message);
  9. }

From MSDN:
Quote
"When an exception occurs in a try block, the system searches the associated catch blocks in the order they appear in application code, until it locates a catch block that handles the exception. A catch block handles an exception of type T if the type filter of the catch block specifies T or any type that T derives from. The system stops searching after it finds the first catch block that handles the exception. For this reason, in application code, a catch block that handles a type must be specified before a catch block that handles its base types, as demonstrated in the example that follows this section. A catch block that handles System.Exception is specified last."

http://msdn.microsoft.com/en-us/library/system.exception.aspx
« Last Edit: April 16, 2012, 02:05:31 PM by exmachina »

Jeff H

  • Needs a day job
  • Posts: 6150
Re: AutoCAD.NET | Handling *Exceptions
« Reply #4 on: April 16, 2012, 09:26:08 PM »
I'm trying to ensure that I am employing a sort of best practices with regard to handling *Exceptions for CommandMethods, and LispFunctions alike.

One recent example came up when I was coding a snippet that incorporates System.IO.Directory.GetParent() Method.

Rather than using If statements to test for valid criteria, I attempted to Catch ArgumentNullException, and ArgumentException, in addition to my normal Autodesk.AutoCAD.Runtime.Exception, yet each instance of my intentionally providing an argument that I thought would trigger one of these GetParent() Method Exceptions resulted in a Fatal Error, rather than hitting the applicable Catch statement.

Any suggestions, or advise would be most helpful.


Pseudo (non-production) code:

Code - C#: [Select]
  1.             try
  2.             {
  3.                 if (args == null)
  4.                 {
  5.                     ed.WriteMessage("\n; error: too few arguments ");
  6.                     return null;
  7.                 }
  8.  
  9.                 Array myArgs = args.AsArray;
  10.                 int i = myArgs.Length;
  11.  
  12.                 if (i > 1)
  13.                 {
  14.                     ed.WriteMessage("\n; error: too many arguments ");
  15.                     return null;
  16.                 }
  17.  
  18.                 if (myArgs(0).TypeCode != LispDataType.Text)
  19.                 {
  20.                     return null;
  21.                 }
  22.  
  23.                 string filePath = ((TypedValue)myArgs.GetValue(0)).Value;
  24.                 DirectoryInfo pathInfo = Directory.GetParent(filePath);
  25.  
  26.                 if (pathInfo.Exists & Directory.Exists(filePath))
  27.                 {
  28.                     return pathInfo.FullName;
  29.                 }
  30.  
  31.             }
  32.             catch (ArgumentNullException ex)
  33.             {
  34.                 ed.WriteMessage("\n; error: " + ex.Message + "\n ");
  35.                 return null;
  36.  
  37.             }
  38.             catch (ArgumentException ex)
  39.             {
  40.                 ed.WriteMessage("\n; error: " + ex.Message + "\n ");
  41.                 return null;
  42.  
  43.             }
  44.             catch (Autodesk.AutoCAD.Runtime.Exception ex)
  45.             {
  46.                 ed.WriteMessage("\n; error: " + ex.Message + "\n ");
  47.                 return null;
  48.  
  49.             }
  50.  

It does not it is null or can't be null until it bubbles back up to calling code.
 
             
Code - C#: [Select]
  1.   if (args == null)
  2.                 {
  3.                     throw new ArgumentNullException();
  4.                 }

BlackBox

  • King Gator
  • Posts: 3770
Re: AutoCAD.NET | Handling *Exceptions
« Reply #5 on: April 16, 2012, 09:44:11 PM »
I didn't realize that I needed to Throw the applicable Exception; I thought that is one of the inherent benefits of using Try... If I must still plan to Throw a particular Exception, the what benefit does Try provide?

** Edit - clearly I have more reading to do on the matter. I'm sure it would help if I went through one of the tutorials too. LoL
« Last Edit: April 16, 2012, 09:55:46 PM by RenderMan »
"How we think determines what we do, and what we do determines what we get."

Jeff H

  • Needs a day job
  • Posts: 6150
Re: AutoCAD.NET | Handling *Exceptions
« Reply #6 on: April 17, 2012, 01:11:16 AM »
Maybe not the best way there but from seeing your small portion of code it is not a good a idea to return null.
 
When it returns null you have no idea the reason why.
The code checks if it is null and if so it returns null and the catch block falls out of scope.

TheMaster

  • Guest
Re: AutoCAD.NET | Handling *Exceptions
« Reply #7 on: April 17, 2012, 04:22:47 PM »
I didn't realize that I needed to Throw the applicable Exception; I thought that is one of the inherent benefits of using Try... If I must still plan to Throw a particular Exception, the what benefit does Try provide?

** Edit - clearly I have more reading to do on the matter. I'm sure it would help if I went through one of the tutorials too. LoL

You use Try when there is a chance that the code that you place in
the Try block will cause an exception that you want to catch. If you
don't catch the exception, it should be caught by AutoCAD's runtime
but perhaps there's something wrong there.

The confusion about using Throw is that you are writing a method
that is called from LISP, so if the arguments passed from the calling
LISP code are wrong, then you can throw an exception, and the
AutoCAD runtime will catch it, and translate it to a LISP error along
with the error message.

Your mistake in that code, is that you are checking arguments passed
from the calling LISP code, and if they're not what you expect, you are
showing a message on the console and returning null, rather than
throwing an exception that triggers a LISP error, which is what should
happen if the arguments are not correct.

That has nothing to do with using Try/Catch to catch an exception that
might be raised by the .NET APIs that you call.

You really don't need to catch argument-related exceptions thrown
by the .NET code you call, you should just let then bubble up and
stop your code. But if there's a fatal error happening, then you only
need to catch System.Exception, and see what the message is. You
can also re-throw the exception back to the calling LISP code as well.

Catching System.Exception is the 'catch-all' case that will catch any
exception, since all exceptions are derived from System.Exception.
E.g., catch( System.Exception ) is like using vl-catch-all-apply, as they
both catch any exception/error thrown.

BlackBox

  • King Gator
  • Posts: 3770
Re: AutoCAD.NET | Handling *Exceptions
« Reply #8 on: April 17, 2012, 04:30:43 PM »
Very informative, Tony... Thank you.
"How we think determines what we do, and what we do determines what we get."

dgorsman

  • Water Moccasin
  • Posts: 2437
Re: AutoCAD.NET | Handling *Exceptions
« Reply #9 on: April 17, 2012, 04:45:47 PM »
There's a few instances I can think of where errors need to be caught, mostly dealing with making sure external resources are properly closed e.g. closing database connections and releasing lock files.
If you are going to fly by the seat of your pants, expect friction burns.

try {GreatPower;}
   catch (notResponsible)
      {NextTime(PlanAhead);}
   finally
      {MasterBasics;}

exmachina

  • Guest
Re: AutoCAD.NET | Handling *Exceptions
« Reply #10 on: April 17, 2012, 05:36:24 PM »
There's a few instances I can think of where errors need to be caught, mostly dealing with making sure external resources are properly closed e.g. closing database connections and releasing lock files.

using Statement ????
http://msdn.microsoft.com/en-us/library/yh598w02.aspx

Any developer should analyze the workflow of your own code and add "catch" blocks  only when needed. Again: here is very well explained
http://msdn.microsoft.com/en-us/library/system.exception.aspx

If you are unsure then use a "clean output"
Code - C#: [Select]
  1. try {
  2.     //anything
  3. } catch {}

It seems that I am the only one who knows reads English ( @ MSDN) :whistle:

TheMaster

  • Guest
Re: AutoCAD.NET | Handling *Exceptions
« Reply #11 on: April 17, 2012, 06:06:30 PM »
There's a few instances I can think of where errors need to be caught, mostly dealing with making sure external resources are properly closed e.g. closing database connections and releasing lock files.

Actually, you don't catch exceptions only to do termination
handling, you use Try/Finally (without Catch), or the Using
construct.
« Last Edit: April 17, 2012, 06:11:01 PM by TheMaster »

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8691
  • AKA Daniel
Re: AutoCAD.NET | Handling *Exceptions
« Reply #12 on: April 17, 2012, 07:35:07 PM »
If you are unsure then use a "clean output"
Code - C#: [Select]
  1. try {
  2.     //anything
  3. } catch {}

This is one snippet of code I truly dislike. I know it's sometimes hard to avoid but it should be used with caution

exmachina

  • Guest
Re: AutoCAD.NET | Handling *Exceptions
« Reply #13 on: April 17, 2012, 08:04:51 PM »
Obviously this must be used in the right environment and with some caution
I use it for "LispFunctions"
Code - C#: [Select]
  1. try {
  2.   //anything
  3. } catch {}
  4.  return null

But this code snippet is present in many more "professional codes" ("commercial" dll's)  than any one could imagine

Jeff H

  • Needs a day job
  • Posts: 6150
Re: AutoCAD.NET | Handling *Exceptions
« Reply #14 on: April 17, 2012, 08:07:46 PM »
There's a few instances I can think of where errors need to be caught, mostly dealing with making sure external resources are properly closed e.g. closing database connections and releasing lock files.

using Statement :? ?
http://msdn.microsoft.com/en-us/library/yh598w02.aspx

Any developer should analyze the workflow of your own code and add "catch" blocks  only when needed. Again: here is very well explained
http://msdn.microsoft.com/en-us/library/system.exception.aspx

If you are unsure then use a "clean output"
Code - C#: [Select]
  1. try {
  2.     //anything
  3. } catch {}

It seems that I am the only one who knows reads English ( @ MSDN) :whistle:

Wow thanks for those great links!!
 
I never have heard of MSDN. I wish I had known about that before.
Oh crap its in English like you mentioned. I can only talk and write in English, but read in Kazakhstaneese.
Oh well.

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8691
  • AKA Daniel
Re: AutoCAD.NET | Handling *Exceptions
« Reply #15 on: April 17, 2012, 08:44:14 PM »
Obviously this must be used in the right environment and with some caution
I use it for "LispFunctions"
Code - C#: [Select]
  1. try {
  2.   //anything
  3. } catch {}
  4.  return null

But this code snippet is present in many more "professional codes" ("commercial" dll's)  than any one could imagine

True,  and it's one of those snippets that gets in your code and you forget about.  IMHO, if you're going to use it, you might want to post out a message on DEBUG builds.  Just to remind you that you have ugly code that can probably be dealt with in a more elegant fashion. 

exmachina

  • Guest
Re: AutoCAD.NET | Handling *Exceptions
« Reply #16 on: April 17, 2012, 08:55:12 PM »
Wow thanks for those great links!!
 
I never have heard of MSDN. I wish I had known about that before.
Oh crap its in English like you mentioned. I can only talk and write in English, but read in Kazakhstaneese.
Oh well.

Therefore I recommend that you read MSDN

I have three hobbies
1. Fishing
2. women
3. programming

It seems that i caught anything, Which will it be?:
cat fish, black bass, walleye or frog?

 :angel: :angel: :angel: :angel:

exmachina

  • Guest
Re: AutoCAD.NET | Handling *Exceptions
« Reply #17 on: April 17, 2012, 09:34:04 PM »
True,  and it's one of those snippets that gets in your code and you forget about.  IMHO, if you're going to use it, you might want to post out a message on DEBUG builds.  Just to remind you that you have ugly code that can probably be dealt with in a more elegant fashion.

I use this to hide a error to the end user. for example: during the execution closes the connection to mysql server, but the user only needs to know if was successful or not.

This can be an eternal discussion: But I think that the two we have felt the same thing on one occasion : "I know it's sometimes hard to avoid but it should be used with caution"

 good night

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: AutoCAD.NET | Handling *Exceptions
« Reply #18 on: April 17, 2012, 10:12:34 PM »
<  ... >
I have three hobbies
1. Fishing
2. women
3. programming



I had to laugh about this;
These are the 3 things that most men lie about ( so I'm told)  :-D
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

exmachina

  • Guest
Re: AutoCAD.NET | Handling *Exceptions
« Reply #19 on: April 18, 2012, 01:32:04 AM »
I had to laugh about this;
These are the 3 things that most men lie about ( so I'm told)  :-D
:laugh: :laugh: :laugh: :laugh: :laugh:
You're probably right. But those are my hobbies, although the order of preference does not correspond to the result
1. I am a good fisherman
2. I'm a bad coder/programmer
3. ... Without comments

Good morning to all!

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8691
  • AKA Daniel
Re: AutoCAD.NET | Handling *Exceptions
« Reply #20 on: April 18, 2012, 03:38:57 AM »
I use this to hide a error to the end user. for example: during the execution closes the connection to mysql server, but the user only needs to know if was successful or not.

See the flaw? Why not catch mysql exceptions and let the exceptional continue on its merry way up the stack ?

exmachina

  • Guest
Re: AutoCAD.NET | Handling *Exceptions
« Reply #21 on: April 18, 2012, 05:20:21 AM »
Sorry, but i dont see any fault.  And in addition i think it has a better performance

Look this:

C# code
Code - C#: [Select]
  1. using MySql.Data.MySqlClient;
  2. namespace ClassLibrary1 {
  3.     public class Class1 {
  4.         public void func1() {
  5.             try {
  6.             } catch (Exception ex) { }
  7.         }
  8.         public void func2() {
  9.             try {
  10.             } catch (MySqlException ex) { }
  11.         }
  12.         public void func3() {
  13.             try {
  14.             } catch  { }
  15.         }
  16.     }
  17. }

IL
Code: [Select]
  .method public hidebysig instance void func1() cil managed
    {
        .maxstack 1
        .locals init (
            [0] class [mscorlib]System.Exception ex)
        L_0000: nop
        L_0001: nop
        L_0002: nop
        L_0003: leave.s L_000a
        L_0005: stloc.0
        L_0006: nop
        L_0007: nop
        L_0008: leave.s L_000a
        L_000a: nop
        L_000b: ret
        .try L_0001 to L_0005 catch [mscorlib]System.Exception handler L_0005 to L_000a
    }

    .method public hidebysig instance void func2() cil managed
    {
        .maxstack 1
        .locals init (
            [0] class [MySql.Data]MySql.Data.MySqlClient.MySqlException ex)
        L_0000: nop
        L_0001: nop
        L_0002: nop
        L_0003: leave.s L_000a
        L_0005: stloc.0
        L_0006: nop
        L_0007: nop
        L_0008: leave.s L_000a
        L_000a: nop
        L_000b: ret
        .try L_0001 to L_0005 catch [MySql.Data]MySql.Data.MySqlClient.MySqlException handler L_0005 to L_000a
    }

    .method public hidebysig instance void func3() cil managed
    {
        .maxstack 1
        L_0000: nop
        L_0001: nop
        L_0002: nop
        L_0003: leave.s L_000a
        L_0005: pop
        L_0006: nop
        L_0007: nop
        L_0008: leave.s L_000a
        L_000a: nop
        L_000b: ret
        .try L_0001 to L_0005 catch object handler L_0005 to L_000a
    }


Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: AutoCAD.NET | Handling *Exceptions
« Reply #22 on: April 18, 2012, 05:57:37 AM »
exmachina (whoknows)

The purpose of a catch statement is generally to handle an exception
... and it is considered good practice to actually handle an  exception, not to ignore it.

Also, when working with database objects ( or any object that should be disposed or closed)
it is usual practice to use a finally statement.

I believe you know this and may be just making your posts to cause a discussion.
If that is the case, please don't, because learners will read these posts
and leave with the wrong impression.


//===========

Your comment about better performance is really
not relevant if the code is not well behaved.

Regards
Kerry   
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

exmachina

  • Guest
Re: AutoCAD.NET | Handling *Exceptions
« Reply #23 on: April 18, 2012, 06:24:58 AM »
...
I believe you know this and may be just making your posts to cause a discussion.
...

No. And i dont like "discussions". But in any case I apologize if I have bothered or offended someone. I had no intention to offend anyone.


...

Your comment about better performance is really
not relevant if the code is not well behaved.

Regards
Kerry

thinking better :I have reason and also I'm wrong
seems that this code (empty catch) can catch all exceptions, even non-CLS compliant exceptions.
« Last Edit: April 18, 2012, 06:29:52 AM by whoknows »

TheMaster

  • Guest
Re: AutoCAD.NET | Handling *Exceptions
« Reply #24 on: April 18, 2012, 06:48:43 AM »
Quote

I use this to hide a error to the end user. for example: during the execution closes the connection to mysql server, but the user only needs to know if was successful or not.


Of course, you can do whatever you think is correct, but if an error happens
for some reason you didn't expect, then you will never know, and the user
will have no way to tell you what's gone wrong.

The point to catching exceptions is to provide a way to find out if an error
you did not expect happens, and what the error is.

Your ideas seem to be predicated on a presumption that your code could
never fail for reasons you didn't expect.

try{} catch {} is like "On Error Resume Next" in legacy VB/VBA, and you
can find plenty of discussion about what's wrong with the latter if you
do the research.

exmachina

  • Guest
Re: AutoCAD.NET | Handling *Exceptions
« Reply #25 on: April 18, 2012, 07:40:09 AM »
Of course, you can do whatever you think is correct, but if an error happens
for some reason you didn't expect, then you will never know, and the user
will have no way to tell you what's gone wrong.
Is intentional. It is a library that provides functions to AutoLisp

Your ideas seem to be predicated on a presumption that your code could
never fail for reasons you didn't expect.
No. It is just the opposite I really think that my code might fail at anything. THIS IS TRUE.It seems that I'm a bit pessimistic

try{} catch {} is like "On Error Resume Next" in legacy VB/VBA, and you
can find plenty of discussion about what's wrong with the latter if you
do the research.
I think I understand how to use try/catch, but today I discovered that is not the same use an empty catch block that a system.exception.
One year ago I had a problem with SEHException (I could not fix) and today I have just discovered that can be  handled with an empty block!!!!! :ugly:

It is true that I come from the VB world and i had many prroblemas to stop using On Error Resume Next and On Error Goto

have a nice day
« Last Edit: April 18, 2012, 07:46:04 AM by whoknows »

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: AutoCAD.NET | Handling *Exceptions
« Reply #26 on: April 18, 2012, 10:00:18 AM »
Hi,

Maybe you can handle Lisp specific exceptions with some classes :

Code - C#: [Select]
  1.     public class LispException : System.Exception
  2.     {
  3.         public LispException(string msg) : base(msg) { }
  4.     }
  5.  
  6.     public class TooFewArgsException : LispException
  7.     {
  8.         public TooFewArgsException() : base("Too few arguments") { }
  9.     }
  10.  
  11.     public class TooManyArgsException : LispException
  12.     {
  13.         public TooManyArgsException() : base("Too many arguments") { }
  14.     }
  15.  
  16.     public class ArgumentTypeException : LispException
  17.     {
  18.         public ArgumentTypeException(string s, TypedValue tv)
  19.             : base(string.Format(
  20.             "Bad argument type: {0} {1}",
  21.             s, tv.TypeCode == (int)LispDataType.Nil ? "nil" : tv.Value))
  22.         { }
  23.     }

The pseudo code in the first post may be this:

Code - C#: [Select]
  1.         [LispFunction("foo")]
  2.         public string Foo(ResultBuffer resbuf)
  3.         {
  4.             Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
  5.             try
  6.             {
  7.                 if (resbuf == null)
  8.                 {
  9.                     throw new TooFewArgsException();
  10.                 }
  11.  
  12.                 TypedValue[] args = resbuf.AsArray();
  13.                 int i = args.Length;
  14.  
  15.                 if (i > 1)
  16.                 {
  17.                     throw new TooManyArgsException();
  18.                 }
  19.  
  20.                 if (args[0].TypeCode != (short)LispDataType.Text)
  21.                 {
  22.                     throw new ArgumentTypeException("stringp", args[0]);
  23.                 }
  24.  
  25.                 string filePath = (string)args[0].Value;
  26.                 DirectoryInfo pathInfo = Directory.GetParent(filePath);
  27.  
  28.                 if (pathInfo.Exists && Directory.Exists(filePath))
  29.                 {
  30.                     return pathInfo.FullName;
  31.                 }
  32.                 else
  33.                 {
  34.                     return null;
  35.                 }
  36.             }
  37.             catch (LispException ex)
  38.             {
  39.                 ed.WriteMessage("\nLISP error: {0}\n", ex.Message);
  40.                 return null;
  41.             }
  42.             catch (Autodesk.AutoCAD.Runtime.Exception ex)
  43.             {
  44.                 ed.WriteMessage("\nAutoCAD error: {0}\n", ex.Message);
  45.                 return null;
  46.             }
  47.             catch (System.Exception ex)
  48.             {
  49.                 ed.WriteMessage("\nSystem error: {0}\n", ex.Message);
  50.                 return null;
  51.             }
  52.         }
  53.     }
Speaking English as a French Frog

BlackBox

  • King Gator
  • Posts: 3770
Re: AutoCAD.NET | Handling *Exceptions
« Reply #27 on: April 18, 2012, 10:03:01 AM »
Most excellent... Thank you for the example code, Gile.
"How we think determines what we do, and what we do determines what we get."

TheMaster

  • Guest
Re: AutoCAD.NET | Handling *Exceptions
« Reply #28 on: April 19, 2012, 05:31:23 PM »
Of course, you can do whatever you think is correct, but if an error happens
for some reason you didn't expect, then you will never know, and the user
will have no way to tell you what's gone wrong.
Is intentional. It is a library that provides functions to AutoLisp

I'm not sure what the calling language has to do with it. 
If the programmer is doing something wrong (e.g., has a
bug in their code), exceptions are how they find out about
them, verses their code running without error, and possibly
corrupting data.

Quote
Your ideas seem to be predicated on a presumption that your code could
never fail for reasons you didn't expect.
No. It is just the opposite I really think that my code might fail at anything. THIS IS TRUE.It seems that I'm a bit pessimistic

try{} catch {} is like "On Error Resume Next" in legacy VB/VBA, and you
can find plenty of discussion about what's wrong with the latter if you
do the research.
I think I understand how to use try/catch, but today I discovered that is not the same use an empty catch block that a system.exception.
One year ago I had a problem with SEHException (I could not fix) and today I have just discovered that can be  handled with an empty block!!!!! :ugly:

It is true that I come from the VB world and i had many prroblemas to stop using On Error Resume Next and On Error Goto

have a nice day

It's true that non-mapped exceptions can't be caught with catch( Exception ex ),
and you have to use catch {}, but catching exceptions isn't the issue, it is not
doing anything when they are caught that is the issue.
« Last Edit: April 19, 2012, 06:12:56 PM by TheMaster »

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: AutoCAD.NET | Handling *Exceptions
« Reply #29 on: May 01, 2012, 09:10:12 AM »
Now here's a nettle for you. Even if I have a throw statement somewhere to return an error to lisp, the wrong error text gets sent to lisp along with an entire error stack trace. E.g.
Code - C#: [Select]
  1.     [LispFunction("SomeLispFunc")]
  2.     public ResultBuffer SomeLispFunc(ResultBuffer args) {
  3.       if (args != null) throw new ArgumentException("Too many arguments");
  4.       // Some more code
  5.     }
Now running that in ACAD:
Code - Auto/Visual Lisp: [Select]
  1. Command: (setq return (vl-catch-all-apply 'SomeLispFunc (list "Test")))
  2. System.ArgumentException: Too many arguments
  3.    at MyLisp.MyLisp.SomeLispFunc(ResultBuffer args)
  4.    at AcMgCommandClass.InvokeWorker(AcMgCommandClass* , MethodInfo mi, Object
  5. commandObject, Boolean bLispFunction)
  6.    at AcMgCommandClass.InvokeWorkerWithExceptionFilter(AcMgCommandClass* ,
  7. MethodInfo mi, Object commandObject, Boolean bLispFunction)
  8.    at AcMgPerDocumentCommandClass.Invoke(AcMgPerDocumentCommandClass* ,
  9. gcroot<System::Reflection::MethodInfo ^>* mi, Boolean bLispFunction)
  10.    at AcMgCommandClass.CommandThunk.InvokeLisp(CommandThunk*
  11. )#<%catch-all-apply-error%>
  12.  
  13. "ADS request error"
And this was tested using both a debug and release build. Doesn't matter if VS started acad, or even if it's running.

So the problem is twofold:
  • I don't want the entire stack trace on the user's command-line, I just want to show him an error message using princ / alert (at worst, probably run some other lisp in case of some type of error). This stack is just clutter to a normal user.
  • The returned message is simply always a "ADS request error" ... so without the stack trace you have no way of passing a custom error back to lisp. And thus you can't distinguish something like a out of bounds exception from a argument exception, making such throws an all or nothing scenario.
At least that's from my understanding & testing. I hope I'm just missing something here, perhaps just a compiler setting or so. Anyone have an idea how to do this?
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: AutoCAD.NET | Handling *Exceptions
« Reply #30 on: May 01, 2012, 09:22:03 AM »
And BTW, that previous samples were done using VS2008 with .Net 3.0 inside Vanilla ACad 2008 on XP32. The same thing still applies if I run the same DLL in Vanilla 2012 on W7-64:
Code - Auto/Visual Lisp: [Select]
  1. Command: (setq return (vl-catch-all-apply 'SomeLispFunc (list "Test")))
  2. System.ArgumentException: Too many arguments
  3.    at MyLisp.MyLisp.SomeLispFunc (ResultBuffer args) in
  4. J:\Programming\MyLisp\MyLisp.cs:line 22
  5.    at Autodesk.AutoCAD.Runtime.CommandClass.InvokeWorker(MethodInfo mi, Object
  6. commandObject, Boolean bLispFunction)
  7.    at
  8. Autodesk.AutoCAD.Runtime.CommandClass.InvokeWorkerWithExceptionFilter(MethodInfo
  9.  mi, Object commandObject, Boolean bLispFunction)
  10.    at Autodesk.AutoCAD.Runtime.PerDocumentCommandClass.Invoke(MethodInfo mi,
  11. Boolean bLispFunction)
  12.    at
  13. Autodesk.AutoCAD.Runtime.CommandClass.CommandThunk.InvokeLisp()#<%catch-all-appl
  14. y-error%>
  15.  
  16. "ADS request error"
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

TheMaster

  • Guest
Re: AutoCAD.NET | Handling *Exceptions
« Reply #31 on: May 01, 2012, 09:47:15 AM »
Now here's a nettle for you. Even if I have a throw statement somewhere to return an error to lisp, the wrong error text gets sent to lisp along with an entire error stack trace.

And this was tested using both a debug and release build. Doesn't matter if VS started acad, or even if it's running.

....
So the problem is twofold:
  • I don't want the entire stack trace on the user's command-line, I just want to show him an error message using princ / alert (at worst, probably run some other lisp in case of some type of error). This stack is just clutter to a normal user.
  • The returned message is simply always a "ADS request error" ... so without the stack trace you have no way of passing a custom error back to lisp. And thus you can't distinguish something like a out of bounds exception from a argument exception, making such throws an all or nothing scenario.
At least that's from my understanding & testing. I hope I'm just missing something here, perhaps just a compiler setting or so. Anyone have an idea how to do this?

I believe that's how it's worked from day 1 (of LispFunction), and I agree that
it's not the right way to handle errors.  For the purpose of catching errors in the
calling LISP, your only option would be to return something signaling a failure
rather than throwing an error. You could return nil to signal that, but in some
cases, nil may be a valid result, so the caller can't distinguish between that and
an error condition.

One way to deal with that is to expose a method that returns the Message
of the exception that was caught during the most recent invocation of one
of your LISP functions:

Code - C#: [Select]
  1.  
  2. public static class Class1
  3. {
  4.  
  5.   static string last_error = null;
  6.  
  7.   [LispFunction("MYLISPFUNCTION")]
  8.   public static object MyLispFuncion( ResultBuffer args )
  9.   {
  10.     last_error = null;
  11.     try
  12.     {
  13.          // code that may fail here
  14.          // or succeed and return a valid result
  15.     }
  16.     catch( SomeSpecialException ex )
  17.     {
  18.        last_error = ex.Message;
  19.        return null;
  20.     }
  21.   }
  22.  
  23.   // LISP user can call this to get the exception message:
  24.  
  25.   [LispFunction("GET-LAST-ERROR")]
  26.   public static string MyLispFuncion( ResultBuffer args )
  27.   {
  28.     return last_error ?? string.Empty;
  29.   }
  30. }
  31.  

If you don't anticipate the error and catch it in managed code, then the
LISP error and stack trace will happen and in most cases, that's what
should happen (the calling LISP code should stop).


irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: AutoCAD.NET | Handling *Exceptions
« Reply #32 on: May 01, 2012, 10:09:07 AM »
Yep, I was thinking along such lines as well. Though I can see a lot of problems if you have more than one assembly doing the same error handling technique: name conflicts spring to mind - thus only the last assembly loaded would define the GET-LAST-ERROR function.

Another thing I've "thought" about  :lmao: is to call a function in lisp which then casts an error. Something like the vl-exit-with-error function. Though that would need a lot of investigation. If I believe the help on the function it would simply end all lisp to the command-line and call the *error* function - no way of catching such with vl-catch-all-apply. Not to mention you'd need some serious coding to use PInvoke to call that function if ACad Version < 2012.
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

TheMaster

  • Guest
Re: AutoCAD.NET | Handling *Exceptions
« Reply #33 on: May 01, 2012, 11:15:04 AM »
Yep, I was thinking along such lines as well. Though I can see a lot of problems if you have more than one assembly doing the same error handling technique: name conflicts spring to mind - thus only the last assembly loaded would define the GET-LAST-ERROR function.

Another thing I've "thought" about  :lmao: is to call a function in lisp which then casts an error. Something like the vl-exit-with-error function. Though that would need a lot of investigation. If I believe the help on the function it would simply end all lisp to the command-line and call the *error* function - no way of catching such with vl-catch-all-apply. Not to mention you'd need some serious coding to use PInvoke to call that function if ACad Version < 2012.

The 'get-last-error' workaround could be shared by many assemblies by adding public methods to set and clear the last error message, so that any number of assemblies could use a single static class for setting/clearing the error, and only that one assembly would define the LISP function needed to retrieve it.

As far as vl-exit-with-error, that was intended for separate namespace VLX code to raise an error, but you still may be able to call it using acedInvoke() or VL.Application. It may require a call to vl-acad-defun to register it for calling via acedInvoke().


GUIDO ROOMS

  • Guest
Re: AutoCAD.NET | Handling *Exceptions
« Reply #34 on: November 18, 2012, 04:31:19 AM »
I'm using the following kludge to circumvent the problem:

1) When certain exceptions occur in a lispfunction (eg. an invalid number of arguments was used to call the function from lisp), I display a message at the prompt, signalling this. So the user or programmer knows there has been an error in
a given function.

2) Then I return an invalid ResultBuffer or TypedValue, that is, one containing an unmatched left parenthesis. That is, I return a New TypedValue(LispDataType.ListBegin,-1) or a resultbuffer containing just that. In this case, the following message is displayed at the autocad prompt: "unclosed :LB in reslist: (:LB)".

3) I redefine the *error* function so that it ignores this string.

The result is that the error gets signalled to users without autocad spewing error messages at the prompt that are incompreshensible to them. And also that the running function or command aborts, if the author of the lispfunction wants that.

Of course, if there's a real error of this kind, an unmatched left parenthesis, the redefined *error* function will hide that, too.
As I mentioned, it's a kludge, not a solution to the problem. But passing nil was no option for me either. Some of my functions have a T or nil result.

(I know this is a reply to an old message, but this way I didn't have to write so much.)
Greetings.




TheMaster

  • Guest
Re: AutoCAD.NET | Handling *Exceptions
« Reply #35 on: November 19, 2012, 12:59:17 AM »
I'm using the following kludge to circumvent the problem:

1) When certain exceptions occur in a lispfunction (eg. an invalid number of arguments was used to call the function from lisp), I display a message at the prompt, signalling this. So the user or programmer knows there has been an error in
a given function.

2) Then I return an invalid ResultBuffer or TypedValue, that is, one containing an unmatched left parenthesis. That is, I return a New TypedValue(LispDataType.ListBegin,-1) or a resultbuffer containing just that. In this case, the following message is displayed at the autocad prompt: "unclosed :LB in reslist: (:LB)".

3) I redefine the *error* function so that it ignores this string.

The result is that the error gets signalled to users without autocad spewing error messages at the prompt that are incompreshensible to them. And also that the running function or command aborts, if the author of the lispfunction wants that.

Of course, if there's a real error of this kind, an unmatched left parenthesis, the redefined *error* function will hide that, too.
As I mentioned, it's a kludge, not a solution to the problem. But passing nil was no option for me either. Some of my functions have a T or nil result.

(I know this is a reply to an old message, but this way I didn't have to write so much.)
Greetings.

Because of an upcoming project where there is going to be a lot of interop between LISP and managed code (about 20-30 lisp functions implemented in managed code), I moved some of the work I had started long ago in support of Lisp/Managed code interop to the front burner, and I've come up with a few things that can help save a LispFunction writer a lot of code.

I've discussed some of it here, and here's another example that can simplify supporting functions that can be called with different arguments or optional arguments:

Code - C#: [Select]
  1. //LispDynamicDispatchExample.cs  copyright 2012 (c) Tony Tanzillo
  2.  
  3. using System;
  4. using System.Linq;
  5. using System.Reflection;
  6. using System.Collections.Generic;
  7. using Autodesk.AutoCAD.ApplicationServices;
  8. using Autodesk.AutoCAD.DatabaseServices;
  9. using Autodesk.AutoCAD.Geometry;
  10. using Autodesk.AutoCAD.Runtime;
  11. using Autodesk.AutoCAD.EditorInput;
  12.  
  13. namespace Lisp.Interop.Dynamic
  14. {
  15.    public static class LispDynamicDispatchExample
  16.    {
  17.       /// <summary>
  18.       ///
  19.       /// Dynamic Dispatch: http://en.wikipedia.org/wiki/Dynamic_dispatch
  20.       ///
  21.       /// The ability to late-bind to one of several overloads of
  22.       /// a method or function, dynamically at runtime, based on
  23.       /// the number and type(s) of a set of given arguments.
  24.       ///
  25.       /// In statically-compiled languages like C or C++, dynamic
  26.       /// dispatch is not supported. In .NET, dynamic dispatch is
  27.       /// supported, but only through the use of System.Dynamic.
  28.       ///
  29.       /// In languages that don't support Dynamic Dispatch, when
  30.       /// multiple overloaded versions of a method are defined,
  31.       /// the version that will be called is determined at compile
  32.       /// time (this is referred to as 'binding'). If no method
  33.       /// matching the given arguments is found, a compile-time
  34.       /// error occurs.
  35.       ///
  36.       /// With dynamic dispatch, the process of binding to methods
  37.       /// is deferred until runtime. Hence, if no matching method can
  38.       /// be found, a runtime error occurs.
  39.       ///
  40.       /// As it turns out, this is an excellent example of how to
  41.       /// leverage the framework and get it to do a lot work for you,
  42.       /// that would otherwise require significant amounts of very
  43.       /// complicated and error-prone code.
  44.       ///
  45.       /// The (dynamic-dispatch) LISP function can be called with
  46.       /// a variety of arguments, as defined by the seven overloads
  47.       /// of the MyLispFunction() method included below. When the
  48.       /// Dispatch() extension method is passed the arguments and
  49.       /// MethodInfo of the caller, it will try to find a matching
  50.       /// overload, and if one is found, it invokes the overload
  51.       /// with the given arguments. If the arguments do not match
  52.       /// one of the overloads, an error is raised.
  53.       ///
  54.       /// LIST arguments are not supported in this demo, but the
  55.       /// ability to support lists is theoretically possible with
  56.       /// some caveats.
  57.       ///
  58.       /// The 'params' modifier that allows a method to accept an
  59.       /// array of any number of arguments of a specified type is
  60.       /// not currently supported. While supporting 'params' may be
  61.       /// possible using custom binding, it would be non-trivial.
  62.       ///
  63.       /// </summary>
  64.    
  65.       /// The "base" method which is called by the AutoCAD
  66.       /// managed runtime when the (dynamic-dispatch) LISP
  67.       /// function is called:
  68.      
  69.       [LispFunction( "dynamic-dispatch" )]
  70.       public static void MyLispFunction( ResultBuffer args )
  71.       {
  72.          args.Dispatch( MethodInfo.GetCurrentMethod() );
  73.       }
  74.  
  75.       /// Below are 7 overloads of the above MyLispFunction() method.
  76.       /// One of those overloads will be called if its argument list
  77.       /// matches the set of arguments passed from LISP (in this case,
  78.       /// 'match' means a method takes the same number of arguments as
  79.       /// was passed from LISP, and that each passed argument can be
  80.       /// assigned to the corresponding method argument variable).
  81.       ///
  82.       /// The overloads must be static methods, with the same name
  83.       /// as the 'base' method that has the LispFunction attribute
  84.       /// applied to it (overloads must NOT have the LispFunction
  85.       /// attribute applied to them).
  86.       ///
  87.       /// Given the set of overloads implemented below, any of the
  88.       /// following calls to (dynamic-dispatch) will succeed:
  89.       ///
  90.       ///    (dynamic-dispatch "foo")
  91.       ///    (dynamic-dispatch "foo" 10)
  92.       ///    (dynamic-dispatch "foo" "bar")
  93.       ///    (dynamic-dispatch pi (getvar "lastpoint"))
  94.       ///    (dynamic-dispatch 2.459 (entlast) "hello")
  95.       ///    (dynamic-dispatch "foo" (ssget "x"))
  96.       ///    (dynamic-dispatch "foo" T)    
  97.       ///    (dynamic-dispatch "foo" NIL)  
  98.       ///
  99.       /// Each of the above calls resolves to a call to one of
  100.       /// the following overloads. Also note that this mechanism
  101.       /// provides for optional arguments in the exact same way
  102.       /// they can be implemented in .NET code, via the use of
  103.       /// method overloading. For example, the first overloaded
  104.       /// function takes a string. The second overload takes a
  105.       /// string and an int, implicitly making the second int
  106.       /// argument optional.
  107.       ///
  108.       /// The functionality provided by the DynamicDispatcher
  109.       /// class achives something that would otherwise require
  110.       /// a sigificant amount of somewhat "messy", error-prone
  111.       /// code.
  112.  
  113.       public static void MyLispFunction( string a )
  114.       {
  115.          Utils.WriteLine( ">>> MyLispFunction( {0} )", a );
  116.       }
  117.  
  118.       public static void MyLispFunction( string a, int b )
  119.       {
  120.          Utils.WriteLine( ">>> MyLispFunction( {0}, {1} )", a, b );
  121.       }
  122.  
  123.       public static void MyLispFunction( double a, Point3d b )
  124.       {
  125.          Utils.WriteLine( ">>> MyLispFunction( {0}, {1} )", a, b );
  126.       }
  127.  
  128.       public static void MyLispFunction( string a, string b )
  129.       {
  130.          Utils.WriteLine( ">>> MyLispFunction( {0}, {1} )", a, b );
  131.       }
  132.  
  133.       public static void MyLispFunction( double a, ObjectId b, string c )
  134.       {
  135.          Utils.WriteLine( ">>> MyLispFunction( {0}, {1}, {2} )", a, b, c );
  136.       }
  137.  
  138.       public static void MyLispFunction( string a, SelectionSet b )
  139.       {
  140.          Utils.WriteLine( ">>> MyLispFunction( {0}, {1} )", a, b );
  141.       }
  142.  
  143.       public static void MyLispFunction()
  144.       {
  145.          Utils.WriteLine( ">>> MyLispFunction()" );
  146.       }
  147.  
  148.       /// To invoke this method you must pass the symbol T or NIL
  149.       /// in the second argument. Contrary to LISP conventions,
  150.       /// no other value is accepted (in LISP, Nil = 'false' and
  151.       /// anything else implies 'true', but that convention can
  152.       /// not be used here without opening a pandora's box that
  153.       /// could lead to selecting the wrong overload).
  154.  
  155.       public static void MyLispFunction( string a, bool b )
  156.       {
  157.          Utils.WriteLine( ">>> MyLispFunction( {0}, {1} )", a, b );
  158.       }
  159.    }
  160.  
  161.    public static class DynamicDispatcher
  162.    {
  163.       const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic
  164.          | BindingFlags.Static | BindingFlags.FlattenHierarchy;
  165.  
  166.       public static object Dispatch( this ResultBuffer args, MethodBase baseMethod )
  167.       {
  168.          if( baseMethod == null )
  169.             throw new ArgumentNullException( "baseMethod" );
  170.          // Validate and pre-process the arguments:
  171.             TypedValue[] array = args != null ? args.Cast<TypedValue>().Select( Validate ).ToArray() : new TypedValue[0];
  172.          // Try to find a matching overload of the caller:
  173.          MethodInfo method = baseMethod.DeclaringType.GetMethod(
  174.             baseMethod.Name, bindingFlags, null,
  175.             array.Select( tv => tv.Value.GetType() ).ToArray(), null );
  176.          if( method == null )
  177.             throw new MissingMethodException( baseMethod.DeclaringType.Name, baseMethod.Name );
  178.          else
  179.          {
  180.             object[] values = array != null ? array.Select( t => t.Value ).ToArray() : null;
  181.             Utils.WriteLine( "\n\nSelected method: {0}:", method.ToString() );
  182.             return method.Invoke( null, values );
  183.          }
  184.       }
  185.  
  186.       public static T Dispatch<T>( this ResultBuffer args, MethodBase baseMethod )
  187.       {
  188.          return (T) Dispatch( args, baseMethod );
  189.       }
  190.  
  191.       static short RTNIL = (short) LispDataType.Nil;
  192.       static short RTT = (short) LispDataType.T_atom;
  193.       static short RTLB = (short) LispDataType.ListBegin;
  194.  
  195.       static TypedValue Validate( TypedValue tv )
  196.       {
  197.          short code = tv.TypeCode;
  198.          if( code == RTNIL )
  199.             return new TypedValue( RTNIL, false ); // interpret NIL as boolean false
  200.          if( code == RTT )
  201.             return new TypedValue( RTT, true );  // interpret T as boolean true
  202.          if( code == RTLB )
  203.             throw new ArgumentException( "lists not supported in this example" );
  204.          if( tv.Value == null )
  205.             throw new ArgumentException( "value cannot be null" );
  206.          return tv;
  207.       }
  208.    }
  209.  
  210.    internal static class Utils
  211.    {
  212.       public static void WriteLine( string fmt, params object[] args )
  213.       {
  214.          Document doc = Application.DocumentManager.MdiActiveDocument;
  215.          if( doc != null )
  216.          {
  217.             string msg = fmt.StartsWith( "\n" ) ? fmt : "\n" + fmt;
  218.             msg = string.Format( msg, args );
  219.             doc.Editor.WriteMessage( msg );
  220.          }
  221.       }
  222.    }
  223.  
  224.    /*  ;; Tester - needs at least one entity in the current drawing:
  225.  
  226.       (defun dynamic-dispatch-test ()
  227.          (dynamic-dispatch "foo")
  228.          (dynamic-dispatch "foo" 10)
  229.          (dynamic-dispatch "foo" "bar")
  230.          (dynamic-dispatch pi (getvar "lastpoint"))
  231.          (dynamic-dispatch 2.459 (entlast) "hello")
  232.          (dynamic-dispatch "foo" (ssget "x"))
  233.          (dynamic-dispatch "foo" T)    
  234.          (dynamic-dispatch "foo" NIL)  
  235.       )
  236. */
  237.  
  238. }
  239.  
« Last Edit: November 19, 2012, 03:17:40 PM by TT »

GUIDO ROOMS

  • Guest
Re: AutoCAD.NET | Handling *Exceptions
« Reply #36 on: November 19, 2012, 12:19:54 PM »
Thanks for the example Tony.
As I wrote yesterday, the thing I came up with was a kludge.
Greetings.

TheMaster

  • Guest
Re: AutoCAD.NET | Handling *Exceptions
« Reply #37 on: November 19, 2012, 10:16:03 PM »
Thanks for the example Tony.
As I wrote yesterday, the thing I came up with was a kludge.
Greetings.

What I posted started out as a kludge, but since posting it, i've figured out how to add support for list arguments as well (with the latest version, you just declare an argument in an overload as 'object[]').  :laugh: