In my code I explode the block reference for the block, I can see all the entities in the collection but entities doesn't have id's in them
[CommandMethod("BlockDefinition")]
public void BlockDefinition()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
using (Transaction trx = db.TransactionManager.StartTransaction())
{
PromptEntityOptions peo = new PromptEntityOptions("\nSelect Block");
peo.SetRejectMessage("Not a Block");
peo.AddAllowedClass(typeof(BlockReference), true);
PromptEntityResult per = ed.GetEntity(peo);
if (per.Status != PromptStatus.OK)
{
return;
}
BlockReference bref = trx.GetObject(per.ObjectId, OpenMode.ForRead) as BlockReference;
BlockTableRecord btr = (BlockTableRecord)trx.GetObject(bref.BlockTableRecord, OpenMode.ForRead);
foreach (ObjectId id in btr)
{
ed.WriteMessage("{0} - {1}\n", id.ObjectClass.DxfName, id.ToString());
}
trx.Commit();
}
}
CIRCLE - (8796082561152)
LINE - (8796082561168)
ARC - (8796082561184)
If you create new non-database-resident objects, you are responsible to Dispose() them. Alternatively, you could wrap the DBObjectCollection itself in a using statement, which would take care of disposing the objects contained when leaving its scope.
Unless it has changed recently, I don't believe DBObjectCollection disposes its elements when it gets disposed.
When a DBObjectCollection is disposed, it looks at the set of unmanaged objects it holds, and the set of wrappers it has generated. For those objects with wrappers, it assumes the wrappers will manage the lifetime of the object, and it does nothing. For those objects without wrappers, it will delete them or close them: it takes responsibility for object lifetime.
...
it is important to be sure DBObjectCollections are properly (perhaps explicitly) disposed.
We've been at it (http://www.theswamp.org/index.php?topic=29303.msg348593#msg348593) before, inconclusively. Even then, under DBObjectCollection Class, arxmgd.chm says:
When a DBObjectCollection is disposed, it looks at the set of unmanaged objects it holds, and the set of wrappers it has generated. For those objects with wrappers, it assumes the wrappers will manage the lifetime of the object, and it does nothing. For those objects without wrappers, it will delete them or close them: it takes responsibility for object lifetime.
...
"Alternatively, you could wrap the DBObjectCollection itself in a using statement, which would take care of disposing the objects contained when leaving its scope."
it is important to be sure DBObjectCollections are properly (perhaps explicitly) disposed.
Maybe as a test, you can copy the dbobjects to another container such as list, call dispose the DBObjectCollection, then call IsDisposed on one of the items... just saying
Select Entity:
28 Objects in collection
28 Objects in list
0: IsDisposed False
1: IsDisposed False
etc.
... Because the destructors of some native objects can make calls to AutoCAD APIs that are not thread-safe, the managed wrappers for those objects must always be disposed (from an AutoCAD thread, where most managed user code runs), to ensure the destructors of the wrapped native objects execute on that same AutoCAD thread.
...We do have to dispose the objects (that aren't added to the Database) and also the DBObjectCollection.
Maybe as a test, you can copy the dbobjects to another container such as list, call dispose the DBObjectCollection, then call IsDisposed on one of the items... just saying
Threading has nothing to do with it. the issue is 'when' to destroy a native pointer within a wrapper, in a garbage collected framework that does not have scoping? A, you don't, you suppress the finalizer and hand it off to the developer then put words like " it's important to dispose the object (perhaps explicitly)" in your documentation. but it is what it is, if you create it and don't hand it off to an owner, dispose it, Easy Peasy Lemon Squeezy
#region
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
#endregion
[assembly: CommandClass(typeof(ExecMethod.Commands))]
namespace ExecMethod
{
public class leak : DBPoint
{
protected override void DeleteUnmanagedObject()
{
System.Windows.Forms.MessageBox.Show("HI : )");
base.DeleteUnmanagedObject();
}
}
public class Commands
{
[CommandMethod("leak")]
public static void leak()
{
leak spring = new leak();
}
}
}
Threading has nothing to do with it. the issue is 'when' to destroy a native pointer within a wrapper, in a garbage collected framework that does not have scoping? A, you don't, you suppress the finalizer and hand it off to the developer then put words like " it's important to dispose the object (perhaps explicitly)" in your documentation. but it is what it is, if you create it and don't hand it off to an owner, dispose it, Easy Peasy Lemon Squeezy
Well, threading has everything to do with why you must determinstically call Dispose() on DBObjects that are not database-resident.
But, in a managed environment with garbage collection, it shouldn't be necessary to call Dispose() on anything, unless there is something special that must occur when the object is no longer used (an example would be a class that manages an open file, where calling Dispose() would cause the file to be closed, allowing others to access it).
Unfortunately, we're stuck with a cooperative fiber-mode application that has many APIs that aren't thread-safe, which means they can only be called on one of the application-managed threads/fibers, and that is the root cause of the utterly-ridiculous Dispose() requirement that vastly-complicates development of managed AutoCAD solutions.
Take the following class as an example. When should the GC call the finalaizer?
How does the GC know that Acad does not need the pointer? it doesn't,
either you hand the task to an owner, such as the transaction manager, or you, the developer must call dispose.. by design :-)
did you run this code? when does the collector fire?
www.theswamp.org/index.php?topic=40630.msg459240#msg459240
additionally, you can derive from disposable wrapper and examine the behavior, you just might be surprised : )
you tell me :lol:
you tell me :lol:
Can't right now, I'm on my netbook, far from my desktop :grin:
Just tell us :lol:
I shouldn't see any anything until the next GC.
And in case you didn't know this, even a simple call to acutPrintF() will fail in that same context (with no exeception or any kind of error message).
public class leak : Line
{
protected override void DeleteUnmanagedObject()
{
Application.ShowAlertDialog("DeleteUnmanagedObject");
HostApplicationServices.WorkingDatabase.Clayer = HostApplicationServices.WorkingDatabase.LayerZero;
base.DeleteUnmanagedObject();
}
protected override void Dispose(bool A_1)
{
Application.ShowAlertDialog("Dispose");
base.Dispose(A_1);
HostApplicationServices.WorkingDatabase.Clayer = HostApplicationServices.WorkingDatabase.LayerZero;
}
}
public class Commands
{
[CommandMethod("leak")]
public static void leak()
{
leak spring = new leak();
spring.LayerId = HostApplicationServices.WorkingDatabase.Clayer;
}
And it goes Boom!!! <runtime>
<generatePublisherEvidence enabled="false"/>
<gcConcurrent enabled="false"/>
</runtime>
Did you quit playing?
I think you got lost :lol:
I get that items such as acutPrintf are not thread safe. it's not even close to what I am taking about.
I am talking about the "lifetime" of an underlying unmanaged object, when wrapped in a class such as disposableWapper.
My goal here is not to argue with you, it's to pass on the little knowledge i have gained from writing literally thousands of wrappers for .NET : ) .
Guys,Are you after Xdata attached to the BlockReference?
I am sitting here and reading through the posts and learning a lot. Thanks for sharing your knowledge with every one.
Jeff,
Thanks for the code sample it worked like a charm but I have one issue, when i get the entities from the BlockTableRecord there is no XData in those entities, does this goes back to that cloning issue again or am I doing something wrong.
< ... > so I added a FartNotifier that plays a different fart sound for Finalize, Dispose, and DeleteUnmanaged Object. Was a little easier and more amusing for me.
< ... >
Unique/Tard same difference :)< ... > so I added a FartNotifier that plays a different fart sound for Finalize, Dispose, and DeleteUnmanaged Object. Was a little easier and more amusing for me.
< ... >
:) I really enjoy how unique some people are !!
For fun I guess someone could use reflection to create a new instance of each object thet derives from DisposableWrapper
For fun I guess someone could use reflection to create a new instance of each object thet derives from DisposableWrapperOff on a tangent: How easy do you think is that done in a reliable manner?
Too many things to think about and I do not know about how vaild it would be.
I probably should not post this as I know it is not a good idea but for a general idea maybe something for listing
Code - C#: [Select]
[CommandMethod("ListAcDbMgdDisposableTypes")] public void ListAcDbMgdDisposableTypes() { Assembly ass = Assembly.Load("acdbmgd"); foreach (AssemblyName assName in ass.GetReferencedAssemblies()) { Assembly.Load(assName.FullName); } Type[] types = ass.GetTypes(); foreach (Type typ in types) { { Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage("\n", typ.Name); } } }
example of how the garbage collector works with DBObjects... when do you see the message :-)