.NET

Reply
Valued Contributor
HelloWorlddd
Posts: 87
Registered: ‎05-03-2013
Message 1 of 7 (481 Views)
Accepted Solution

Managed and unmanaged resources

481 Views, 6 Replies
12-24-2013 07:43 AM

   I have too many questions that need to understand, so I list  these questions below
   My main question is about release of managed and unmanaged resources
   First I copied the help documentation about the IDisposable Interface and Using statement from MSDN  as the basis


IDisposable Interface
   Defines a method to release allocated resources.
   Remarks
   The primary use of this interface is to release unmanaged resources. The garbage collector automatically releases the memory allocated to a managed object when that object is no longer used. However, it is not possible to predict when garbage collection will occur. Furthermore, the garbage collector has no knowledge of unmanaged resources such as window handles, or open files and streams.
   Use the Dispose method of this interface to explicitly release unmanaged resources in conjunction with the garbage collector. The consumer of an object can call this method when the object is no longer needed. 
   Calling the IDisposable Interface
   When calling a class that implements the IDisposable interface, use the try/finally pattern to make sure that unmanaged resources are disposed of even if an exception interrupts your application.


Using statement
   Using statement will then automatically handle unmanaged resources,using Statement will Provides a convenient syntax that ensures the correct use of IDisposable objects.
   File and Font are examples of managed types that access unmanaged resources (in this case file handles and device contexts). There are many other kinds of unmanaged resources and class library types that encapsulate them. All such types must implement the IDisposable interface.
   As a rule, when you use an IDisposable object, you should declare and instantiate it in a using statement. The using statement calls the Dispose method on the object in the correct way, and (when you use it as shown earlier) it also causes the object itself to go out of scope as soon as Dispose is called. Within the using block, the object is read-only and cannot be modified or reassigned.
   The using statement ensures that Dispose is called even if an exception occurs while you are calling methods on the object.

 

Now begin my question

 

   Quesiton 1:

   Which one is a  unmanaged resources?


   For example, the TransactionObject is a unmanaged resources, is’t right? Then the LineObject is a unmanaged resources too?


   Question 2:

    Resources must be in brackets?
    What’s the difference between the following code:


    Using(resource object)
    {
    }


    Using()
    {
    resource object
    }

 

   Question 3:

    The line class has implemented the IDiposable interface, then it is a managed or unmanaged resources?

    Whether it is that I need instantiate a Line Object in the Using statement?

 

   Question 4:

    Why databases, documents are not needed in the using statement.


   For example:
  [CommandMethod("AdskGreeting")]
        public void AdskGreeting()
        {
            Document acDoc = Application.DocumentManager.MdiActiveDocument;
            Database acCurDb = acDoc.Database;

            using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction())
            {
                BlockTable acBlkTbl = acTrans.GetObject(acCurDb.BlockTableId, OpenMode.ForRead) as BlockTable;
                BlockTableRecord acBlkTblRec = acTrans.GetObject(acBlkTbl[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;
                MText objText = new MText();
                objText.SetDatabaseDefaults();
                objText.Location = new Autodesk.AutoCAD.Geometry.Point3d(2, 2, 0);
                objText.Contents = "Greetings, Welcome to the AutoCAD .NET";
                objText.TextStyleId = acCurDb.Textstyle;
                acBlkTblRec.AppendEntity(objText);
                acTrans.AddNewlyCreatedDBObject(objText, true);
                acTrans.Commit();
            }
        }


   Question 5:

   Programming  with AtuoCAD, just feeling like programming with database,  is that AtuoCAD can be called a object oriented database?


   Quesiton 6:

   During open the object by the ObjectID to obtain objects from the database,And with AppendEntity and AddNewlyCreatedDBObject method is to add objects to the database, it that Open and Add operation is to use unmanaged resources , This process is just as open a Txt file?

 

  For example:
  BlockTable blockTableObj = currentTransactionObj.GetObject(acurrentDataBase.BlockTableId, OpenMode.ForRead) as BlockTable;

 

  ObjectId acCircId = blockTableRecordObj.AppendEntity(firstCircleObj);
  currentTransactionObj.AddNewlyCreatedDBObject(firstCircleObj, true);

 

 

   Thanks very much, Merry Christmas!

 

In the "unsafe" example, a new circle is created to be passed as argument to the CircleJig constructor.
Then the user is prompted to specify the circle center.
The user may specify a point or cancel the command during the prompt (or an exception may occur).
In the first case (the user specified a point), the newly created circle is added to transanction and so will be automatically disposed whith the transaction disposing.
In the second case (the user cancellled), the newly created circle is not added to the transaction, so it won't be diposed whith the transaction disposing, and AutocAD may crash sometimes after.
This is why I called this example "unsafe".
 
So if you're absolutely certain a newly created object will be added to a transaction, you can avoid to explicitly dispose it.
In all others cases, you have to dispose it explicitly (if this wasn't necessary, this is not an issue, disposing the transaction won't dispose again already disposed objects).
Tony Tanzillo, a well known and very talented AutoCAD programmer recommends as better practice to always dipose newly created database resident objects. IOW, always use:
using (Circle circle = new Circle()) { ... } or using (Line line = new Line()) { ... } and so on...
 
You can put the using expression at the same level of the transaction one or nest it in the transaction statement.

 

using (Transaction tr = db.TransactionManager.StartTransaction())
using (Circle circle = new Circle(Point3d.Origin, Vector3d.ZAxis, 10.0))
{
} // <- the circle and the transaction will be disposed here

 works the same as:

using (Transaction tr = db.TransactionManager.StartTransaction())
{
using (Circle circle = new Circle(Point3d.Origin, Vector3d.ZAxis, 10.0))
{
} // <- the circle will be disposed here
} // <- the transaction will be disposed here

 

*Expert Elite*
_gile
Posts: 2,114
Registered: ‎04-29-2006
Message 2 of 7 (454 Views)

Re : Managed and unmanaged resources

12-24-2013 09:03 AM in reply to: HelloWorlddd

Hi,

 

Shortly.

 

It's a better practice to use a using statement which insure the object will be disposed even if an exception occurs.

 

Always dispose instances of Transaction and DocumentLock.

 

Any object opened with the transaction using Transaction.GetObject or ObjectId.GetObject() or added to the Transaction using Transaction.AddNewlyCreatedObject()  will be automatically disposed when the Transaction is disposed.

 

Any newly created object (with new) have to be explicitly disposed if it is not (or possibly may not be) added to the Transaction.

 

Anyway, while you're not certain a disposable object need to be disposed or will be automatically disposed, do dispose it explicitly.

 

Example with unusefull statement which works:

using (Transaction tr = db.TransactionManager.StartTransaction())
{
    // this is unusefull because the object is opened with the transaction, but works
    using (BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite))
    {
        // this is unusefull because the circle will be added to the Transaction, but works
        using (Circle circle = new Circle(Point3d.Origin, Vector3d.ZAxis, 10.0))
        {
            btr.AppendEntity(circle);
            tr.AddNewlyCreatedDBObject(circle, true);
        }
    }
    tr.Commit();
}

 The previous example would have been safely written:

using (Transaction tr = db.TransactionManager.StartTransaction())
{
    BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
    Circle circle = new Circle(Point3d.Origin, Vector3d.ZAxis, 10.0);
    btr.AppendEntity(circle);
    tr.AddNewlyCreatedDBObject(circle, true);
    tr.Commit();
}

 

Example of unsafe code: it's needed to create a new circle instance to use with CircleJig but the circle will only be added to the transaction if Editor.Drag().Status is equal to PromptStatus.OK. If no (the use cancelled), the new Circle won't be disposed.

using (Transaction tr = db.TransactionManager.StartTransaction())
{
    BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
    Circle circle = new Circle(Point3d.Origin, Vector3d.ZAxis, 10.0);
    CircleJig jig = new CircleJig(circle);
    if (ed.Drag(jig).Status == PromptStatus.OK)
    {
        btr.AppendEntity(circle);
        tr.AddNewlyCreatedDBObject(circle, true);
    }
    tr.Commit();
}

 Here's a safe way to write the upper code (note you can have many using statements)

using (Transaction tr = db.TransactionManager.StartTransaction())
using (Circle circle = new Circle(Point3d.Origin, Vector3d.ZAxis, 10.0))
{
    BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
    CircleJig jig = new CircleJig(circle);
    if (ed.Drag(jig).Status == PromptStatus.OK)
    {
        btr.AppendEntity(circle);
        tr.AddNewlyCreatedDBObject(circle, true);
    }
    tr.Commit();
}

 

Gilles Chanteau
*Expert Elite*
_gile
Posts: 2,114
Registered: ‎04-29-2006
Message 3 of 7 (443 Views)

Re : Managed and unmanaged resources

12-24-2013 09:28 AM in reply to: _gile

You can read this (long) discussion at TheSwamp.

Gilles Chanteau
Valued Contributor
HelloWorlddd
Posts: 87
Registered: ‎05-03-2013
Message 4 of 7 (434 Views)

Re : Managed and unmanaged resources

12-24-2013 10:00 AM in reply to: _gile

   I was a little confused, did not find the nuances between them, can you explainit a little more clearly?

   Especially do not understand this long sentence: ” Example of unsafe code: it's needed to create a new circle instance to use with CircleJig but the circle will only be added to the transaction if Editor.Drag().Status is equal to PromptStatus.OK. If no (the use cancelled), the new Circle won't be disposed.”

 

   First, you give me the first sample code, It’s a nest Using statement
   Using(express1)
   {
     Using(express2)
      {
      statement
      }
   }


   The first sample code would have been safely written:


   Using(express)
   {
    statement
   }

 

   Then,you show me the third sample code, it’s will use the Jig, but It’s unsafe


   Using(express)
   {
    statement
   }

 

   Finally, you tell me the safe code should be.


   Using(express1)
   Using(express2)
   {
   statement
   }

 

   I understand already


   Using(express1)
   Using(express2)
   {
    statement
   }


   is equivalent to


   Using(express1,express2)
  {
    statement
   }

 

   I can conclude:


   Express is not equivalent to statement, 
   It’s not just transaction object requires in brackets behind the Using


   So,which one should be in the brackets behind the Using?
   I guess the one should be unmanage resources, but for the some circle, sometimes it can be instance at the statement position or choose a nest way instance at the statement position, sometimes it must be instance at the express position…


   Continue to confusinggg…more help, grateful:smileyhappy:

 

*Expert Elite*
_gile
Posts: 2,114
Registered: ‎04-29-2006
Message 5 of 7 (399 Views)

Re : Managed and unmanaged resources

12-25-2013 02:46 AM in reply to: HelloWorlddd

In the "unsafe" example, a new circle is created to be passed as argument to the CircleJig constructor.
Then the user is prompted to specify the circle center.
The user may specify a point or cancel the command during the prompt (or an exception may occur).
In the first case (the user specified a point), the newly created circle is added to transanction and so will be automatically disposed whith the transaction disposing.
In the second case (the user cancellled), the newly created circle is not added to the transaction, so it won't be diposed whith the transaction disposing, and AutocAD may crash sometimes after.
This is why I called this example "unsafe".
 
So if you're absolutely certain a newly created object will be added to a transaction, you can avoid to explicitly dispose it.
In all others cases, you have to dispose it explicitly (if this wasn't necessary, this is not an issue, disposing the transaction won't dispose again already disposed objects).
Tony Tanzillo, a well known and very talented AutoCAD programmer recommends as better practice to always dipose newly created database resident objects. IOW, always use:
using (Circle circle = new Circle()) { ... } or using (Line line = new Line()) { ... } and so on...
 
You can put the using expression at the same level of the transaction one or nest it in the transaction statement.

 

using (Transaction tr = db.TransactionManager.StartTransaction())
using (Circle circle = new Circle(Point3d.Origin, Vector3d.ZAxis, 10.0))
{
    
} // <- the circle and the transaction will be disposed here

 works the same as:

using (Transaction tr = db.TransactionManager.StartTransaction())
{
    using (Circle circle = new Circle(Point3d.Origin, Vector3d.ZAxis, 10.0))
    {
        
    } // <- the circle will be disposed here
} // <- the transaction will be disposed here

 

Gilles Chanteau
Valued Contributor
HelloWorlddd
Posts: 87
Registered: ‎05-03-2013
Message 6 of 7 (371 Views)

Re : Managed and unmanaged resources

12-26-2013 08:57 AM in reply to: _gile

I think I finally understand the reason
The key is the Using statement will finally execute dispose() for a resource object that in the brackets

 

Follow is the description of the Transaction manager copy from the AutoCAD .NET Developer's Guide
As you work with objects opened with GetObject, the Transaction manager keeps track of the changes that are being made to the object. Any new objects that you create and add to the database should be added to a transaction as well with the AddNewlyCreatedDBObject function. Once the objects have been edited or added to the database, you can save the changes made to the database and close all the open objects with the Commit function on the Transaction object created with the Transaction Manager. Once you are finished with a transaction, call the Dispose function close the transaction.

 

General situation, use the transaction,


1,will execute the transactionObject.GetObject()
2,or will execute the AddNewlyCreatedDBObject (),

 

for example
Using (transactionObject..)
{
transactionObject.GetObject()
new object
AddNewlyCreatedDBObject (object)
}
Finally, each object open or add to the transaction will execute dispose() by default, and inculde the transaction itself will execute dispose()


However, if an exception occurs between the new Entityobject() and AddNewlyCreatedDBObject(), not enough time to add new objects to the transaction, for example
Using (transactionObject..)
{
new entityObject()
throw new Exception
AddNewlyCreatedDBObject (Entityobject)
}
Finally, the Using statement will execute transactionObject.dispose () itslef only by default. But won’t execute the entityObject.dispose (), because of the Transaction Manager can't track the new entitiyObject

 

So, It’s the best way always dipose newly created database resident objects as you recommend,

Using()

Using()

.

.

{

 

}

thank you very much.

Active Member
nini18110
Posts: 6
Registered: ‎07-16-2014
Message 7 of 7 (33 Views)

Re: Managed and unmanaged objects to appendentity

11-20-2014 02:50 AM in reply to: HelloWorlddd

I am unable to exexute the modelspace.appendentity with mu sustom class object.

 

using(Transaction trans = db.TransactionManager.StartTransaction())

{

 

using (BlockTable bt = trans.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable)

{

 

using (BlockTableRecord modelSpace =

trans.GetObject(bt[

 

BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord)

{

 

 

Point3d ecsLinePt1;

 

 

Point3d wLinePt1;

 

 

Point3d ecsLinePt2;

 

 

Point3d wLinePt2;

 

 

// transform the hot spot points based on the axis they chose

ecsLinePt1 = newItem.pt1.TransformBy(

 

Matrix3d.WorldToPlane(norm));

ecsLinePt2 = newItem.pt2.TransformBy(

 

Matrix3d.WorldToPlane(norm));

 

 

// if its supposed to be horizontal, make sure you set the x,y coords right

 

 

if (bHorz)

ecsLinePt2 =

 

new Point3d(ecsLinePt2.X, ecsLinePt1.Y, ecsLinePt1.Z);

 

 

else

ecsLinePt2 =

 

new Point3d(ecsLinePt1.X, ecsLinePt2.Y, ecsLinePt1.Z);

 

 

// now that the coords are right put them back into world coords

wLinePt1 = ecsLinePt1.TransformBy(

 

Matrix3d.PlaneToWorld(norm));

wLinePt2 = ecsLinePt2.TransformBy(

 

Matrix3d.PlaneToWorld(norm));

 

 

double dimScale = db.Dimscale;

 

 

double gap = 0.1800 * dimScale;

 

 

double offset = 0.0625 * dimScale;

 

 

double txtHgt = 0.1 * dimScale;

 

 

// transform the line points into plane coords

ecsLinePt1 = wLinePt1.TransformBy(

 

Matrix3d.WorldToPlane(norm));

ecsLinePt2 = wLinePt2.TransformBy(

 

Matrix3d.WorldToPlane(norm));

 

 

int tmpLevel = level;

 

 

if (level == 99)

tmpLevel = 10;

 

 

// determine how far out the line pts are

 

 

// supposed to be relative to the hot spot

 

 

Point3d tmpPt = wLinePt1.TransformBy(Matrix3d.Displacement(new Vector3d(0, 1 * .11, 0)));

 

 

Point3d wEp13d = wLinePt1 + (extLineAng1 * (txtHgt * (tmpLevel + 1)));

 

 

Point3d wEp23d = wLinePt2 + (extLineAng2 * (txtHgt * (tmpLevel + 1)));

 

 

// draw the line

 

 

LineSegment3d tmpEdgeLine = new LineSegment3d(wEp13d, wEp23d);

 

 

 

TRNEDDPAdimMgd mg = new TRNEDDPAdimMgd();

 

 

 

// get the midpoint which

 

 

// is where we'll put the text

 

 

Point3d txtEp1 = tmpEdgeLine.MidPoint;

mg.Normal = norm;

mg.TextPt = txtEp1;

 

 

// set text for the hot spot names

mg.DimFrom = resolvedItem.hs1;

mg.DimTo = resolvedItem.hs2;

 

 

// set text for the symbol

mg.DimSymbol = adimName;

 

 

// set text for the desc

mg.DimDescr = adimDesc;

mg.AxisOn = axis;

mg.DimPlane = plane;

mg.ViewCode = face;

mg.Level = level;

 

 

// set the points that will create the

 

 

// line that is parallel to the hot spot

mg.LinePt1 = wLinePt1;

mg.LinePt2 = wLinePt2;

 

 

// set the pts where the hot spots are

mg.StartPt = wEp13d;

mg.EndPt = wEp23d;

 

 

if (layerId != ObjectId.Null)

mg.LayerId = layerId;

 

 

// add this to model space

modelSpace.AppendEntity(mg);

 

 

// notify the transaction

trans.AddNewlyCreatedDBObject(mg,

 

true);

 

 

// save changes

trans.Commit();

 

 

 

 

here TRNEDDPAdimMgd mg = new TRNEDDPAdimMgd(); is the custom class i am using .

 

Post to the Community

Have questions about Autodesk products? Ask the community.

New Post
Announcements
Are You Going To Be @ AU 2014? Feel free to drop by our AU topic post and share your plans, plug a class that you're teaching, or simply check out who else from the community might be in attendance. Ohh and don't forgot to stop by the Autodesk Help | Learn | Collaborate booths in the Exhibit Hall and meet our community team if you get a chance!