Author Topic: using (DocumentLock ....  (Read 3294 times)

0 Members and 1 Guest are viewing this topic.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
using (DocumentLock ....
« on: March 24, 2011, 03:20:29 AM »

To lock a document prior to making changes to the database normally I'd do something like this ;

Code: [Select]
           // Start a transaction
            using( DocumentLock docLock = doc.LockDocument() ) {
                using( Transaction tr = db.TransactionManager.StartTransaction() ) {
                    BlockTable bt;
                    BlockTableRecord btr;
                    try {
                        // Open Model space for write
                        bt = tr.GetObject(db.BlockTableId,
                                                     OpenMode.ForRead) as BlockTable;
                        btr = tr.GetObject(bt[ BlockTableRecord.ModelSpace ],
                                                        OpenMode.ForWrite) as BlockTableRecord;
                       // < snip >


Today I quickly added a DocumentLock without really paying attention and didn't add the asignment to a variable
ie :
Code: [Select]
           // Start a transaction
            using( doc.LockDocument() ) {
                using( Transaction tr = db.TransactionManager.StartTransaction() ) {
                    BlockTable bt;
                    BlockTableRecord btr;
                    try {
                        // Open Model space for write
                        bt = tr.GetObject(db.BlockTableId,
                                                     OpenMode.ForRead) as BlockTable;
                        btr = tr.GetObject(bt[ BlockTableRecord.ModelSpace ],
                                                        OpenMode.ForWrite) as BlockTableRecord;
                       // < snip >


The code performed flawlessly

Questions:
Has anyone come across this previously ?
Any thoughts on the veracity of the idea that the asignment is not needed if the variable is not used in the code block that follows ?
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.

pkohut

  • Bull Frog
  • Posts: 483
Re: using (DocumentLock ....
« Reply #1 on: March 24, 2011, 05:06:19 AM »
Makes sense, the object returned from doc.LockDocument will go out of scope at the end of the using block.

edit:
With the first method, does C# give a warning that docLock is unused?
« Last Edit: March 24, 2011, 05:09:39 AM by pkohut »
New tread (not retired) - public repo at https://github.com/pkohut

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: using (DocumentLock ....
« Reply #2 on: March 24, 2011, 05:29:19 AM »
Makes sense, the object returned from doc.LockDocument will go out of scope at the end of the using block.

edit:
With the first method, does C# give a warning that docLock is unused?

No message Paul.
I was just looking at the ILDASM code .. very interesting how the compiler changes the code in the first snip to be as my second snip anyway ... I'll post shortly.
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.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: using (DocumentLock ....
« Reply #3 on: March 24, 2011, 05:38:46 AM »

The first snip here is the original code
The second is the reflector view on the IL code in the DLL.

Note that the input tests and return statement have been revised to be in-line.

the
using( DocumentLock docLock = doc.LockDocument() ) {
has been changed to
using (doc.LockDocument())

The using( Transaction tr = db.TransactionManager.StartTransaction() ) {
has been shanged to
 Transaction tr = db.TransactionManager.StartTransaction();
... I assume because of the DockLock using statement.

The start of the try statement has been changed.

The finally statement has been added.

ORIGINAL SOURCE
Code: [Select]
       [CommandMethod("GP1", CommandFlags.Session)]
        public static void GetPointsFromUser_1()
        {
            // Get the current database and start the Transaction Manager
            Document doc = AcadApp.DocumentManager.MdiActiveDocument;           
            Database db = doc.Database;
            Editor ed = doc.Editor;

            PromptPointResult pPtRes;
            PromptPointOptions pPtOpts = new PromptPointOptions("");

            // Prompt for the start point, Point3D will be in current UCS
            pPtOpts.Message = "\nEnter the start point of the line: ";
            pPtRes = doc.Editor.GetPoint(pPtOpts);

            // Exit if the user presses ESC or cancels the command
            if( pPtRes.Status == PromptStatus.Cancel )
                return;
            //
            Point3d ptStart = pPtRes.Value;

            // Prompt for the end point, Point3D will be in current UCS           
            pPtOpts.Message = "\nEnter the end point of the line: ";
            pPtOpts.UseBasePoint = true;
            pPtOpts.BasePoint = ptStart;
            pPtRes = doc.Editor.GetPoint(pPtOpts);

            if( pPtRes.Status == PromptStatus.Cancel )
                return;
            //
            Point3d ptEnd = pPtRes.Value;

            // Convert the UCS points to WCS
            Point3d ptStartW = ptStart.UcsToWcs();
            Point3d ptEndW = ptEnd.UcsToWcs();

            // Start a transaction
            using( DocumentLock docLock = doc.LockDocument() ) {
                using( Transaction tr = db.TransactionManager.StartTransaction() ) {
                    BlockTable bt;
                    BlockTableRecord btr;
                    try {
                        // Open Model space for write
                        bt = tr.GetObject(db.BlockTableId,
                                                     OpenMode.ForRead) as BlockTable;
                        btr = tr.GetObject(bt[ BlockTableRecord.ModelSpace ],
                                                        OpenMode.ForWrite) as BlockTableRecord;

                        // Define the new line using the WCS Ordinates
                        Line acLine = new Line(ptStartW, ptEndW);
                        acLine.SetDatabaseDefaults();

                        // Add the line to the drawing
                        btr.AppendEntity(acLine);
                        tr.AddNewlyCreatedDBObject(acLine, true);

                        // Commit the changes and dispose of the transaction
                        tr.Commit();

                    } catch( Autodesk.AutoCAD.Runtime.Exception exx ) {
                        ed.WriteMessage("\n" + exx.ToString());
                    }
                }
                // Zoom to the extents or limits of the drawing
                doc.SendStringToExecute("._zoom _all ", true, false, false);
            }
        }

TRANSLATED IL CODE
Code: [Select]
[CommandMethod("GP1", CommandFlags.Session)]
public static void GetPointsFromUser_1()
{
    Document doc = Application.DocumentManager.MdiActiveDocument;
    Database db = doc.Database;
    Editor ed = doc.Editor;
    PromptPointOptions pPtOpts = new PromptPointOptions("") {
        Message = "\nEnter the start point of the line: "
    };
    PromptPointResult pPtRes = doc.Editor.GetPoint(pPtOpts);
    if (pPtRes.Status != PromptStatus.Cancel)
    {
        Point3d ptStart = pPtRes.Value;
        pPtOpts.Message = "\nEnter the end point of the line: ";
        pPtOpts.UseBasePoint = true;
        pPtOpts.BasePoint = ptStart;
        pPtRes = doc.Editor.GetPoint(pPtOpts);
        if (pPtRes.Status != PromptStatus.Cancel)
        {
            Point3d ptEnd = pPtRes.Value;
            Point3d ptStartW = ptStart.UcsToWcs();
            Point3d ptEndW = ptEnd.UcsToWcs();
            using (doc.LockDocument())
            {
                Transaction tr = db.TransactionManager.StartTransaction();
                try
                {
                    BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
                    BlockTableRecord btr = tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;
                    Line acLine = new Line(ptStartW, ptEndW);
                    acLine.SetDatabaseDefaults();
                    btr.AppendEntity(acLine);
                    tr.AddNewlyCreatedDBObject(acLine, true);
                    tr.Commit();
                }
                catch (Exception exx)
                {
                    ed.WriteMessage("\n" + exx.ToString());
                }
                finally
                {
                    if (tr != null)
                    {
                        tr.Dispose();
                    }
                }
                doc.SendStringToExecute("._zoom _all ", true, false, false);
            }
        }
    }
}

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.

dan.glassman

  • Guest
Re: using (DocumentLock ....
« Reply #4 on: March 24, 2011, 09:57:05 AM »
The docs do say that using (expression) is supported, doing exactly what I'd want it to do.  The result of the expression is still explicitly .Disposed() rather than relying on the gc (can see this by looking at the IL in reflector).

As for the other changes you note...what version of VS?  With 2010 targeting .Net 3.5, I'm seeing the nested usings preserved.  The other changes you note remain.

Quote from: VS2010 targeting 3.5, via Reflector
using (doc.LockDocument())
{
    using (Transaction tr = db.TransactionManager.StartTransaction())
    {
        try
        {
            BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
            BlockTableRecord btr = tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;
            Line acLine = new Line(ptStartW, ptEndW);
            acLine.SetDatabaseDefaults();
            btr.AppendEntity(acLine);
            tr.AddNewlyCreatedDBObject(acLine, true);
            tr.Commit();
        }
        catch (Exception exx)
        {
            ed.WriteMessage("\n" + exx.ToString());
        }
    }
}


Unrelated to the disassembly, you can remove a level of indentation in the original source if you like; same nested result as above in reflector (using VS2010, again).

Code: [Select]
using (doc.LockDocument())
using (Transaction tr = db.TransactionManager.StartTransaction())
{
    BlockTable bt;
    BlockTableRecord btr;
    ...
}
doc.SendStringToExecute(...);
« Last Edit: March 24, 2011, 10:04:43 AM by dan.glassman »

T.Willey

  • Needs a day job
  • Posts: 5251
Re: using (DocumentLock ....
« Reply #5 on: March 24, 2011, 10:11:08 AM »
I just started doing it that way this week Kerry.  The way I figure it is that I'm not using the variable anywhere, but within the using call it will still get disposed.  Seemed to make sense to me, and the compiler didn't complain, as you note ( SharpDevelop ).
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

mohnston

  • Bull Frog
  • Posts: 305
  • CAD Programmer
Re: using (DocumentLock ....
« Reply #6 on: March 24, 2011, 12:12:23 PM »
Very interesting thread.

I wonder if this would compile:

using (doc.LockDocument())
{
    using (db.TransactionManager.StartTransaction())
    {
       // do something that doesn't need a transaction here
    }
}

Don't know how that would be of any value.
It's amazing what you can do when you don't know what you can't do.
CAD Programming Solutions