Author Topic: test for object type by Is or casting...  (Read 9604 times)

0 Members and 1 Guest are viewing this topic.

jmaeding

  • Bull Frog
  • Posts: 304
  • I'm just here for the Shelties.
test for object type by Is or casting...
« on: December 17, 2009, 04:52:57 PM »
I brach code a fair amount, based on object type.
I say:
if (obj is Polyline) then....

I could also try casting with as:
Polyline lwp = obj as Polyline;
then test for null:
if (lwp != null) {....

I would think testing object lineage, then casting once is better than casting over and over until one succeeds.
Is one approach faster than the other?
James Maeding

Glenn R

  • Guest
Re: test for object type by Is or casting...
« Reply #1 on: December 17, 2009, 05:01:54 PM »
Direct cast will blow up in your face if it isn't what you're expecting; checking with 'as' won't.

Typical usage if you're not quite sure is something like this:

Code: [Select]
Line l = tr.GetObject(SomeObjectIdObtainedFromElsewhere, OpenMode.ForRead, false) as Line;
If (l != null)
{
  // some interesting mojo goes here
}

Myself, if I know it's going to be 'X' (example, one of the symbol tables) I now prefer a direct cast like so:

Code: [Select]
Line l = (Line)tr.GetObject(SomeObjectIdObtainedFromElsewhere, OpenMode.ForRead, false);

I think this is slightly more efficient because using 'as' does a test first then returns object or null, whereas a direct cast will do exactly that - cast directly.

My 2p worth.

You didn't respond in the VCS thread as to how you're getting on with SourceGear Vault...thoughts?

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: test for object type by Is or casting...
« Reply #2 on: December 17, 2009, 05:18:02 PM »
< ..>
My 2p worth.


wow, you've sure been assimilated.
All the best to you and yours for a sparkling white Christmas Glenn.
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.

Glenn R

  • Guest
Re: test for object type by Is or casting...
« Reply #3 on: December 17, 2009, 05:23:49 PM »
hehe...had to think about that one actually...was naturally going to write 2c :)

Thanks for the best wishes Kerry - same to you and yours as well. Actually, we had snow in London itself on Wednesday (rare) and at home, where it's now snowing again. Weather forecast says up to 200mm by tomorrow in south-east which is me...Yay! Knock off on holidays a day early with any luck.

sinc

  • Guest
Re: test for object type by Is or casting...
« Reply #4 on: December 17, 2009, 07:35:23 PM »
It would be easy enough to come up with a little test, and try something like 100,000 of each, and see what the difference is.

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8698
  • AKA Daniel
Re: test for object type by Is or casting...
« Reply #5 on: December 17, 2009, 07:46:10 PM »
Microsoft recommends the 'as' and test for null method  :-)

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: test for object type by Is or casting...
« Reply #6 on: December 17, 2009, 08:10:53 PM »

James, are you using AutoCAD 2009 or later ?

You MAY be able to use the ObjectClass property of ObjectId

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.

David Hall

  • Automatic Duh Generator
  • King Gator
  • Posts: 4075
Re: test for object type by Is or casting...
« Reply #7 on: December 18, 2009, 10:14:57 AM »
Microsoft recommends the 'as' and test for null method  :-)
Is that because it wont blow up as badly or b/c they are lazy?
Everyone has a photographic memory, Some just don't have film.
They say money can't buy happiness, but it can buy Bacon and that's a close second.
Sometimes the question is more important than the answer. (Thanks Kerry for reminding me)

David Hall

  • Automatic Duh Generator
  • King Gator
  • Posts: 4075
Re: test for object type by Is or casting...
« Reply #8 on: December 18, 2009, 10:18:49 AM »
Glenn, in both your examples, you used ObjectIds you had previously obtained.  I am assuming that in the first example, there was no filtering, so there could be anything obtained.  But in the second, you KNOW you have a line, so cast the object to a line, Right?  I guess I am of the mind to filter my selection ahead of time so as to "know" what Im working with.  Is that what you were getting at?
Everyone has a photographic memory, Some just don't have film.
They say money can't buy happiness, but it can buy Bacon and that's a close second.
Sometimes the question is more important than the answer. (Thanks Kerry for reminding me)

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: test for object type by Is or casting...
« Reply #9 on: December 18, 2009, 06:48:08 PM »
because someone is probably going to ask :-

no animals were harmed in the execution of this code.
added:
Requires AutoCAD 2009 or later
and no casts were try'd


Code - C#: [Select]
  1. // (C) CodeHimBelonga kdub @TheSwamp 20091219
  2. //
  3. using System;
  4. using System.Text;
  5. using System.Runtime.CompilerServices;
  6. using System.Runtime.InteropServices;
  7.  
  8. using Autodesk.AutoCAD.Runtime;
  9. using Autodesk.AutoCAD.ApplicationServices;
  10. using Autodesk.AutoCAD.DatabaseServices;
  11. using Autodesk.AutoCAD.Geometry;
  12. using Autodesk.AutoCAD.EditorInput;
  13.  
  14. using AcadApp = Autodesk.AutoCAD.ApplicationServices.Application;
  15.  
  16. // This line is not mandatory, but improves loading performances
  17. [assembly: CommandClass(typeof(KDUB_testing.MyTestCommands))]
  18.  
  19. namespace KDUB_testing
  20. {
  21.     public class MyTestCommands
  22.     {
  23.         [CommandMethod("SOOS")]
  24.         public static void SelectObjectsOnScreen()
  25.         {
  26.             // Get the current document and database
  27.             Document doc = AcadApp.DocumentManager.MdiActiveDocument;
  28.             Database db = doc.Database;
  29.  
  30.             int lineCount = 0, circleCount = 0, polylineCount = 0, mtextCount = 0,
  31.                 blockreferenceCount = 0, otherStuff = 0;
  32.  
  33.             // Request for objects to be selected in the drawing area
  34.             PromptSelectionResult acSSPrompt = doc.Editor.GetSelection();
  35.  
  36.             // If the prompt status is OK, objects were selected
  37.             if (acSSPrompt.Status == PromptStatus.OK)
  38.             {
  39.                 SelectionSet acSSet = acSSPrompt.Value;
  40.  
  41.                 // Step through the objects in the selection set
  42.                 foreach (SelectedObject acSSObj in acSSet)
  43.                 {
  44.                     //AcadApp.ShowAlertDialog(acSSObj.ObjectId.ObjectClass.Name);
  45.  
  46.                     switch (acSSObj.ObjectId.ObjectClass.Name)
  47.                     {
  48.                         case "AcDbLine":
  49.                             lineCount++;
  50.                             break;
  51.                         case "AcDbCircle":
  52.                             circleCount++;
  53.                             break;
  54.                         case "AcDbPolyline":
  55.                             polylineCount++;
  56.                             break;
  57.                         case "AcDbMText":
  58.                             mtextCount++;
  59.                             break;
  60.                         case "AcDbBlockReference":
  61.                             blockreferenceCount++;
  62.                             break;
  63.                         default:
  64.                             otherStuff++;
  65.                             break;
  66.  
  67.                     }
  68.                 }
  69.                 AcadApp.ShowAlertDialog
  70.                     ("lineCount = " + lineCount.ToString()
  71.                         + "\ncircleCount = " + circleCount.ToString()
  72.                         + "\npolylineCount = " + polylineCount.ToString()
  73.                         + "\nmtextCount = " + mtextCount.ToString()
  74.                         + "\nblockreferenceCount = " + blockreferenceCount.ToString()
  75.                         + "\notherStuff = " + otherStuff.ToString()
  76.                     );
  77.             }
  78.         }
  79.  
  80.     }
  81. }

and the obligatory attachment :
« Last Edit: January 25, 2012, 07:05:45 PM by 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.

sinc

  • Guest
Re: test for object type by Is or casting...
« Reply #10 on: December 18, 2009, 07:35:31 PM »
Can you just compare the ObjectClass directly, rather than the ObjectClass.Name?  I'm wondering if it might be faster, especially since all the names start with "AcDb"...

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: test for object type by Is or casting...
« Reply #11 on: December 18, 2009, 08:15:17 PM »
probably doable;
by using the RXClass.IsDerivedfrom(..) Method

Quote
Returns true if Class == this or if the class represented by this Class object is descended from the class represented by the Class object pointed to by Class. Otherwise returns false.


but I doubt it would be significantly more economical
... and you couldn't use switch-case conditional. .. ( but thats no biggie)
... and you'd need to define the RXClass to test against
something like
RXClass whateverImTestingAgainstRXClass = RXObject.GetClass(typeof(whateverImTestingAgainst)) ;

either way, it will be faster than directcasting or as

but I'd be interested in seeing a test :)

« Last Edit: December 18, 2009, 08:23:19 PM by Kerry Brown »
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.

Glenn R

  • Guest
Re: test for object type by Is or casting...
« Reply #12 on: December 19, 2009, 08:23:00 AM »
Glenn, in both your examples, you used ObjectIds you had previously obtained.  I am assuming that in the first example, there was no filtering, so there could be anything obtained.  But in the second, you KNOW you have a line, so cast the object to a line, Right?  I guess I am of the mind to filter my selection ahead of time so as to "know" what Im working with.  Is that what you were getting at?

Duh, I just tossed those examples off, but essentially, yes. If you're opening one of the symbol tables, you know it's a symboltable, so I direct cast.

Bryco

  • Water Moccasin
  • Posts: 1883
Re: test for object type by Is or casting...
« Reply #13 on: December 19, 2009, 02:41:52 PM »
Code: [Select]
    class Cast
    {

        [CommandMethod("tes")]
        public void Test1()
        {
            Document doc = acadApp.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
            PromptEntityResult per = ed.GetEntity("\nSelect a curve: ");

            if (per.Status != PromptStatus.OK) return;
            ObjectId id = per.ObjectId;
            Polyline pl;
            ed.WriteMessage("\nYou selected a " + id.ObjectClass.DxfName);           

            long start = DateTime.Now.Ticks;
            for (int i = 0; i < 10000; i++)
            {
                using (Transaction tr = db.TransactionManager.StartTransaction())
                {
                    pl = tr.GetObject(id, OpenMode.ForRead) as Polyline;
                    if (pl == null)
                    {
                        tr.Commit();
                        continue;
                    }
                    tr.Commit();
                }
            }

            ed.WriteMessage("\nAs test ellapsed time ="
                + ((DateTime.Now.Ticks - start) / 1000).ToString());




            //use this only if you pick a polyline

            //start = DateTime.Now.Ticks;
            //for (int i = 0; i < 10000; i++)
            //{
            //    using (Transaction tr = db.TransactionManager.StartTransaction())
            //    {
            //        pl = (Polyline)tr.GetObject(id, OpenMode.ForRead);
            //        tr.Commit();
            //    }
            //}

            //ed.WriteMessage("\nDirect test ellapsed time ="
            //    + ((DateTime.Now.Ticks - start) / 1000).ToString());


            pl = null;
            start = DateTime.Now.Ticks;
            for (int i = 0; i < 10000; i++)
            {
                using (Transaction tr = db.TransactionManager.StartTransaction())
                {
                    Entity ent = tr.GetObject(id, OpenMode.ForRead) as Entity;
                    if (ent is Polyline)
                        pl = tr.GetObject(id, OpenMode.ForRead) as Polyline;
                    tr.Commit();
                }
            }
            ed.WriteMessage("\nIs test using as method ellapsed time ="
                + ((DateTime.Now.Ticks - start) / 1000).ToString());




            start = DateTime.Now.Ticks;
            for (int i = 0; i < 10000; i++)
            {
                using (Transaction tr = db.TransactionManager.StartTransaction())
                {
                    Entity ent = tr.GetObject(id, OpenMode.ForRead) as Entity;
                    if (ent is Polyline)
                        pl = (Polyline)tr.GetObject(id, OpenMode.ForRead);                 
                    tr.Commit();
                }
            }
            ed.WriteMessage("\nIs test using direct cast method ellapsed time ="
                + ((DateTime.Now.Ticks - start) / 1000).ToString());




            start = DateTime.Now.Ticks;
            for (int i = 0; i < 10000; i++)
            {
                using (Transaction tr = db.TransactionManager.StartTransaction())
                {
                    if(id.ObjectClass==RXClass.GetClass(typeof( Polyline)))
                        pl =(Polyline) tr.GetObject(id, OpenMode.ForRead);
                    tr.Commit();
                }
               
            }
            ed.WriteMessage("\ndirect cast using id., ellapsed time ="
                + ((DateTime.Now.Ticks - start) / 1000).ToString());




            start = DateTime.Now.Ticks;
            RXClass plineClass = RXClass.GetClass(typeof(Polyline));
            for (int i = 0; i < 10000; i++)
            {
                using (Transaction tr = db.TransactionManager.StartTransaction())
                {
                    if (id.ObjectClass == plineClass)
                        pl = (Polyline)tr.GetObject(id, OpenMode.ForRead);
                    tr.Commit();
                }
            }

            ed.WriteMessage("\ndirect cast using pre dimmed class, ellapsed time ="
                + ((DateTime.Now.Ticks - start) / 1000).ToString());



            start = DateTime.Now.Ticks;
            for (int i = 0; i < 10000; i++)
            {
                using (Transaction tr = db.TransactionManager.StartTransaction())
                {
                    if (id.ObjectClass == plineClass)
                        pl = tr.GetObject(id, OpenMode.ForRead)as Polyline;
                    tr.Commit();
                }
            }

            ed.WriteMessage("\nAs cast using pre dimmed class, ellapsed time ="
                + ((DateTime.Now.Ticks - start) / 1000).ToString());





            start = DateTime.Now.Ticks;
            for (int i = 0; i < 10000; i++)
            {
                using (Transaction tr = db.TransactionManager.StartTransaction())
                {
                    if (id.ObjectClass.Name == "AcDbPolyline")
                        pl = (Polyline)tr.GetObject(id, OpenMode.ForRead);
                    tr.Commit();
                }
            }

            ed.WriteMessage("\ndirect cast using id string comparison, ellapsed time ="
                + ((DateTime.Now.Ticks - start) / 1000).ToString());



            start = DateTime.Now.Ticks;
            for (int i = 0; i < 10000; i++)
            {
                using (Transaction tr = db.TransactionManager.StartTransaction())
                {
                    if (id.ObjectClass.Name == "AcDbPolyline")
                        pl = tr.GetObject(id, OpenMode.ForRead) as Polyline;
                    tr.Commit();
                }
            }

            ed.WriteMessage("\nAs cast using id string comparison, ellapsed time ="
                + ((DateTime.Now.Ticks - start) / 1000).ToString());



            start = DateTime.Now.Ticks;
            for (int i = 0; i < 10000; i++)
            {
                using (Transaction tr = db.TransactionManager.StartTransaction())
                {
                    if (id.ObjectClass.DxfName == "LWPOLYLINE")
                        pl = tr.GetObject(id, OpenMode.ForRead) as Polyline;
                    tr.Commit();
                }
            }

            ed.WriteMessage("\nAs cast using id dxf string comparison, ellapsed time ="
                + ((DateTime.Now.Ticks - start) / 1000).ToString());







        } //end  Test1

    } //End Cast

Bryco

  • Water Moccasin
  • Posts: 1883
Re: test for object type by Is or casting...
« Reply #14 on: December 19, 2009, 02:42:43 PM »
Command:  TES
Select a curve:
You selected a LWPOLYLINE
As test ellapsed time =2000
Direct test ellapsed time =2000
Is test using as method ellapsed time =2480
Is test using direct cast method ellapsed time =2520
direct cast using id., ellapsed time =17010
direct cast using pre dimmed class, ellapsed time =2230
As cast using pre dimmed class, ellapsed time =2300
direct cast using id string comparison, ellapsed time =2370
As cast using id string comparison, ellapsed time =2330
As cast using id dxf string comparison, ellapsed time =2310
Command:
Automatic save to C:\Users\kabry\appdata\local\temp\Drawing1_1_1_6827.sv$ ...

Command:
Command:
Command:  TES
Select a curve:
You selected a CIRCLE
As test ellapsed time =2130
Is test using as method ellapsed time =2150
Is test using direct cast method ellapsed time =2110
direct cast using id., ellapsed time =15800
direct cast using pre dimmed class, ellapsed time =1460
As cast using pre dimmed class, ellapsed time =1430
direct cast using id string comparison, ellapsed time =1490
As cast using id string comparison, ellapsed time =1510
As cast using id dxf string comparison, ellapsed time =1480