A while back, we talked about various ways of object type checking in AutoCAD .NET and listed out the pros and cons of each approach. We even did some small tiny experiments to compare their performances. Some readers also suggested good ideas such as using the StopWatch instead of the TimeSpan and moving code out of the loop if possible on how to improve the preciseness of the testing results.
In this post, let’s summarize some points again and clarify something that was not clear enough before.
We still apply the following four approaches:
• Using the keyword ‘is’ to check what type the object of concern is.
• Retrieving the Type from the object of concern through calling the GetType() method against it and doing a comparison to the target type which can be got using the .NET typeof keyword.
• Comparing the ObjectClass instance of the object of concern with the target one.
• Comparing the DxfName property of the object of concern with an arbitrary string.
Here are the improved versions of the test code and commands:
[CommandMethod("TestVariousTypeCheckA")]
public static void TestVariousTypeCheckA_Method()
{
Editor ed = MgdAcApplication.DocumentManager.MdiActiveDocument.Editor;
Stopwatch watch = new Stopwatch();
watch.Restart();
int count = TypeCheckApproach1().Count;
watch.Stop();
ed.WriteMessage("Time elapsed in TypeCheckApproach1 for {0} circles: {1}\n", count, watch.Elapsed.TotalMilliseconds);
watch.Restart();
count = TypeCheckApproach2().Count;
watch.Stop();
ed.WriteMessage("Time elapsed in TypeCheckApproach2 for {0} circles: {1}\n", count, watch.Elapsed.TotalMilliseconds);
watch.Restart();
count = TypeCheckApproach2A().Count;
watch.Stop();
ed.WriteMessage("Time elapsed in TypeCheckApproach2A for {0} circles: {1}\n", count, watch.Elapsed.TotalMilliseconds);
watch.Restart();
count = TypeCheckApproach3().Count;
watch.Stop();
ed.WriteMessage("Time elapsed in TypeCheckApproach3 for {0} circles: {1}\n", count, watch.Elapsed.TotalMilliseconds);
watch.Restart();
count = TypeCheckApproach3A().Count;
watch.Stop();
ed.WriteMessage("Time elapsed in TypeCheckApproach3A for {0} circles: {1}\n", count, watch.Elapsed.TotalMilliseconds);
watch.Restart();
count = TypeCheckApproach4().Count;
watch.Stop();
ed.WriteMessage("Time elapsed in TypeCheckApproach4 for {0} circles: {1}\n", count, watch.Elapsed.TotalMilliseconds);
watch.Restart();
count = TypeCheckApproach5().Count;
watch.Stop();
ed.WriteMessage("Time elapsed in TypeCheckApproach5 for {0} circles: {1}\n", count, watch.Elapsed.TotalMilliseconds);
}
public static ObjectIdCollection TypeCheckApproach1()
{
ObjectIdCollection ids = new ObjectIdCollection();
Database db = HostApplicationServices.WorkingDatabase;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
BlockTableRecord btr = tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForRead) as BlockTableRecord;
foreach (ObjectId id in btr)
{
DBObject obj = tr.GetObject(id, OpenMode.ForRead);
if (obj is Circle)
{
ids.Add(obj.Id);
}
}
tr.Commit();
}
return ids;
}
public static ObjectIdCollection TypeCheckApproach2()
{
ObjectIdCollection ids = new ObjectIdCollection();
Database db = HostApplicationServices.WorkingDatabase;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
BlockTableRecord btr = tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForRead) as BlockTableRecord;
foreach (ObjectId id in btr)
{
DBObject obj = tr.GetObject(id, OpenMode.ForRead);
if (obj.GetType() == typeof(Circle))
{
ids.Add(obj.Id);
}
}
tr.Commit();
}
return ids;
}
public static ObjectIdCollection TypeCheckApproach2A()
{
ObjectIdCollection ids = new ObjectIdCollection();
Database db = HostApplicationServices.WorkingDatabase;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
BlockTableRecord btr = tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForRead) as BlockTableRecord;
Type t = typeof(Circle);
foreach (ObjectId id in btr)
{
DBObject obj = tr.GetObject(id, OpenMode.ForRead);
if (obj.GetType() == t)
{
ids.Add(obj.Id);
}
}
tr.Commit();
}
return ids;
}
public static ObjectIdCollection TypeCheckApproach3()
{
ObjectIdCollection ids = new ObjectIdCollection();
Database db = HostApplicationServices.WorkingDatabase;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
BlockTableRecord btr = tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForRead) as BlockTableRecord;
foreach (ObjectId id in btr)
{
if (id.ObjectClass == RXObject.GetClass(typeof(Circle)))
{
ids.Add(id);
}
}
tr.Commit();
}
return ids;
}
public static ObjectIdCollection TypeCheckApproach3A()
{
ObjectIdCollection ids = new ObjectIdCollection();
Database db = HostApplicationServices.WorkingDatabase;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
BlockTableRecord btr = tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForRead) as BlockTableRecord;
RXClass CircleClass = RXClass.GetClass(typeof(Circle));
foreach (ObjectId id in btr)
{
if (id.ObjectClass == CircleClass)
{
ids.Add(id);
}
}
tr.Commit();
}
return ids;
}
public static ObjectIdCollection TypeCheckApproach4()
{
ObjectIdCollection ids = new ObjectIdCollection();
Database db = HostApplicationServices.WorkingDatabase;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
BlockTableRecord btr = tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForRead) as BlockTableRecord;
foreach (ObjectId id in btr)
{
if (id.ObjectClass.DxfName == "CIRCLE")
{
ids.Add(id);
}
}
tr.Commit();
}
return ids;
}
public static ObjectIdCollection TypeCheckApproach5()
{
ObjectIdCollection ids = new ObjectIdCollection();
Database db = HostApplicationServices.WorkingDatabase;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
BlockTableRecord btr = tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForRead) as BlockTableRecord;
foreach (ObjectId id in btr)
{
Circle obj = tr.GetObject(id, OpenMode.ForRead) as Circle;
if (obj != null)
{
ids.Add(obj.Id);
}
}
tr.Commit();
}
return ids;
}
Here is the output data:
Command: TESTVARIOUSTYPECHECKA
Time elapsed in TypeCheckApproach1 for 5000 circles: 118.2025
Time elapsed in TypeCheckApproach2 for 5000 circles: 104.0364
Time elapsed in TypeCheckApproach2A for 5000 circles: 102.4317
Time elapsed in TypeCheckApproach3 for 5000 circles: 1436.8256
Time elapsed in TypeCheckApproach3A for 5000 circles: 19.8097
Time elapsed in TypeCheckApproach4 for 5000 circles: 22.0924
In terms of the results, to make the data more objective, some other entities such as 5000 lines and points besides the original 5000 circles were created into the same drawing too this time. As can be seen, two more tests were also added, one for the typeof method and the other one for the RXClass one.
As can be seen, moving the typeof call out of the loop did improve the performance, but not a lot. However, moving the RXClass.GetClass call out of the loop made huge difference, the ObjectClass/RXClass method jumped to the first place now with using about 10% less time than the DxfName approach. However, this does not really indicate that the ObjectClass/RXClass approach is always the best. Rather, it only applies to the similar case as we demonstrated here, looping through the same rather objects with huge amount. If we’d like to check each object type and determine what to do next, the performance of the ObjectClass/RXClass will be seriously deteriorated as the result of the test #3 yielded since the RXObject.GetClass() call has a lot of overheads apparently.
The leading edge AutoCAD .NET Addin Wizard (AcadNetAddinWizard) provides various project wizards, item wizards, coders and widgets to help program AutoCAD .NET addins.
Posted by: |