Author Topic: Kean Walmsley on Dispose()  (Read 8439 times)

0 Members and 1 Guest are viewing this topic.

TheMaster

  • Guest
Kean Walmsley on Dispose()
« on: August 23, 2012, 09:15:56 AM »
Well, I think we knew this was coming :grin:

Kean points out that the MSDN docs here say that it is not recommended to use using() with a variable whose scope exceeds the scope of the using() block, but what he doesn't mention is that when you have a foreach() block enclosing nothing but a using() block (or visa-verse), they both have the same effective scope, and in fact, you can enforce that by using only a single set of curly braces:

In other words, this:

Code - C#: [Select]
  1.   using (var brep = new Brep(path))
  2.   {
  3.     foreach (var face in brep.Faces)
  4.     {
  5.       using (var surf = face.Surface)
  6.       {
  7.            // code here omitted for brevity
  8.       }
  9.       face.Dispose();
  10.     }
  11.   }
  12.  

is functionally equivalent to this:

Code - C#: [Select]
  1.    using (var brep = new Brep(path))
  2.    foreach (var face in brep.Faces)
  3.    using( face )
  4.    using (var surf = face.Surface)
  5.    {
  6.        // same code omitted above, omitted here as well
  7.    }
  8.  

Notice there's only one pair of curly braces that act as the scope delimiters of everything passed to the using() and foreach() statements preceding the open curly brace, and that serves to eliminate any room for error, namely the one given in the example in the referenced MSDN docs, where the code erroneously uses a variable passed to using() after it's been disposed.

So, take that recommendation in the MSDN docs with a grain of salt, and by just using a bit of common sense it should be clear that it's not necessarily applicable in every situation.

I was going to post this in the comments on Kean's blog but you can't post comments with formatted code there.

TheMaster

  • Guest
Re: Kean Walmsley on Dispose()
« Reply #1 on: August 23, 2012, 09:45:31 AM »
One more thing that Kean mentions is AutoCAD crashing at shutdown because the destructor of a C++ object that was left on the heap executed too late in the shutdown process, or on a non-AutoCAD thread, and that's a legitimate reason why a managed wrapper for a native C++ object with a badly-designed destructor needs to be disposed.

One of the problems I've always had with 'overly-aggressive' use of Dispose() is that it results in code that's greatly more complex and difficult to follow. So, what I do is use my abstract ExtensionApplication class that I posted a watered-down version of here to manage IDisposables that need to be Disposed before AutoCAD terminates.

Code - C#: [Select]
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using Autodesk.AutoCAD.ApplicationServices;
  6.  
  7. namespace Autodesk.AutoCAD.Runtime
  8. {
  9.    public abstract class ExtensionApplication : IExtensionApplication
  10.    {
  11.       void IExtensionApplication.Initialize()
  12.       {
  13.          try
  14.          {
  15.             this.Initialize();
  16.          }
  17.          catch( System.Exception ex )
  18.          {
  19.             Console.Beep();
  20.             WriteMessage( "\nAn error occured while loading {0}:\n\n{1}",
  21.               this.GetType().Assembly.Location,
  22.               ex.ToString()
  23.             );
  24.             throw ex;
  25.          }
  26.       }
  27.  
  28.       static void WriteMessage( string fmt, params object[] args )
  29.       {
  30.          Document doc = ApplicationServices.Application.DocumentManager.MdiActiveDocument;
  31.          if( doc != null )
  32.             doc.Editor.WriteMessage( fmt, args );
  33.       }
  34.  
  35.       // Derived types must override this to do initialization
  36.       // and do not need to worry about catching exceptions:
  37.  
  38.       protected abstract void Initialize();
  39.  
  40.       // Derived types can optionally override this to do finalization:
  41.       protected virtual void Terminate()
  42.       {
  43.       }
  44.  
  45.       void IExtensionApplication.Terminate()
  46.       {
  47.          try
  48.          {
  49.             this.Terminate();
  50.             if( Terminating != null )
  51.                Terminating( this, EventArgs.Empty );
  52.          }
  53.          finally
  54.          {
  55.             Terminating = null;
  56.             if( disposables != null )
  57.             {
  58.                disposables.Dispose();
  59.                disposables = null;
  60.             }
  61.          }
  62.       }
  63.  
  64.       // This event can be handled as an alternative way
  65.       // of doing termination handling:
  66.  
  67.       public static event EventHandler Terminating = null;
  68.  
  69.       static DisposableList<IDisposable> disposables = new DisposableList<IDisposable>();
  70.  
  71.       // Pass this method any IDisposable and it will be disposed before
  72.       // AutoCAD shuts down, when the Terminate() method is called.
  73.  
  74.       public static void AddDisposable( IDisposable disposable )
  75.       {
  76.          if( disposables != null )
  77.             disposables.Add( disposable );
  78.       }
  79.  
  80.       public static bool RemoveDisposable( IDisposable disposable )
  81.       {
  82.          if( disposables != null )
  83.             return disposables.Remove( disposable );
  84.          else
  85.             return false;
  86.       }
  87.  
  88.       public static bool ContainsDisposable( IDisposable disposable )
  89.       {
  90.          if( disposables != null )
  91.             return disposables.Contains( disposable );
  92.          else
  93.             return false;
  94.       }
  95.  
  96.    }
  97. }
  98.  
  99. // DisposableList.cs
  100.  
  101. namespace System.Collections.Generic
  102. {
  103.    public class DisposableList<T> : List<T>, IDisposable
  104.       where T : IDisposable
  105.    {
  106.       bool disposed = false;
  107.  
  108.       /// <summary>
  109.       /// If true, contained items are disposed of in reverse order
  110.       /// (last to first).
  111.       ///
  112.       /// Default value: false
  113.       /// </summary>
  114.  
  115.       bool ReverseOrderedDispose
  116.       {
  117.          get;
  118.          set;
  119.       }
  120.  
  121.       public DisposableList()
  122.       {
  123.       }
  124.  
  125.       public DisposableList( int capacity )
  126.          : base( capacity )
  127.       {
  128.       }
  129.  
  130.       public DisposableList( IEnumerable<T> collection )
  131.          : base( collection )
  132.       {
  133.       }
  134.  
  135.       public DisposableList( System.Collections.IEnumerable collection )
  136.          : base( collection.Cast<T>() )
  137.       {
  138.       }
  139.  
  140.       public void Dispose()
  141.       {
  142.          Dispose( true );
  143.       }
  144.  
  145.       protected virtual void Dispose( bool disposing )
  146.       {
  147.          bool flag = this.disposed;
  148.          this.disposed = true;
  149.          if( disposing && !flag )
  150.          {
  151.             if( this.ReverseOrderedDispose )
  152.                base.Reverse();
  153.             using( IEnumerator<T> e = base.GetEnumerator() )
  154.                DisposeItems( e );
  155.          }
  156.       }
  157.  
  158.       private void DisposeItems( IEnumerator<T> e )
  159.       {
  160.          while( e.MoveNext() )
  161.          {
  162.             try
  163.             {
  164.                T item = e.Current;
  165.                if( item != null )
  166.                   item.Dispose();
  167.             }
  168.             catch
  169.             {
  170.                DisposeItems( e );
  171.                throw;
  172.             }
  173.          }
  174.       }
  175.    }
  176.  
  177. }
  178.  
  179. // Example use:
  180.  
  181. [assembly: ExtensionApplication( typeof( MyApplication ) )]
  182.  
  183. public class MyApplication : ExtensionApplication
  184. {
  185.   protected override void Initialize()
  186.   {
  187.     // Do initialization here
  188.  
  189.     // Create an object that implements IDisposable and
  190.     // let ExtensionApplication manage it:
  191.     ExtensionApplication.AddDisposable( myDisposable );
  192.  
  193.   }
  194. }
  195.  
  196.  
« Last Edit: August 23, 2012, 05:37:01 PM by TT »

TheMaster

  • Guest
Re: Kean Walmsley on Dispose()
« Reply #2 on: August 23, 2012, 09:54:13 AM »
And one more thing.... :grin:

Quote from: kean
One thing that’s a little peculiar with the Brep API is that you’re actually forcing a Dispose() on objects that are properties of the Brep object itself (objects that are instantiated when you access the property). That doesn’t always seem right – you would expect the using block around the Brep object to force a Dispose() on all associated objects created/exposed via its properties – but this a quirk of the Brep API that needs special attention, and a big reason the GC-driven finalisation of unmanaged objects seems to rear its ugly head more often when it’s used.

The fact that many 'owned' objects implement IDisposable is coincidental to their deriving from DisposableWrapper, and RXObject.

Kean says nothing about the AutoDelete property, which is false if the native object should not be deleted when its managed wrapper is Disposed, and that's usually the case with managed wrappers for aggregate objects that are owned by some other native object, which is responsible for managing their lifetime and deleting them.

As I think I mentioned previously, if you're not sure about the need to dispose something, just check its AutoDelete property. If it's false, then the odds are that you are either not supposed to dispose it, or don't need to.
« Last Edit: August 23, 2012, 10:24:57 AM by TT »

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: Kean Walmsley on Dispose()
« Reply #3 on: August 23, 2012, 10:08:08 AM »
if you're not sure about the need to dispose something, just check its AutoDelete property. If it's false, then the odds are that you are either not supposed to delete it, or don't need to.

Does that mean this would be acceptable in all cases where you are deleting an object?
Code - C#: [Select]
  1. if ( MyObject.AutoDelete )
  2. {
  3.      MyObject.Delete();
  4. }

I have never understood the AutoDelete property and your description makes it seem counter-intuitive i.e. if AutoDelete is false it is automatically handled? It seems it should be the other way around unless I am missing something.
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

TheMaster

  • Guest
Re: Kean Walmsley on Dispose()
« Reply #4 on: August 23, 2012, 10:19:30 AM »


This was a comment I just posted on Kean's blog, regarding his analysis on this subject.

Quote

Kean, this is more directed at Fenton's advice regarding Dispose(), but neither his nor any of your posts on this topic so much as graze one important aspect of the question, which is the DisposableWrapper's AutoDelete property.

If this property is false, the wrapped native object is not deleted when its managed wrapper is disposed, and disposing a managed wrapper whose AutoDelete property is false, is both pointless and a source of code obfuscation. 

And, if one is going to check the value of this property and use it as a guide for deciding to Dispose the managed wrapper, then one must remember that the managed wrapper can change its value depending on certain conditions. For example, the Database managed wrapper sets this property to true only when the wrapped AcDbDabase was created via a call to ReadDwgFile(). For databases that are open in the drawing editor, the value of AutoDelete is false.

I think it's a bit silly for everyone to be debating this issue when the value of that property literally and definitively answers that question for many (but not all) objects, don't you agree?

If we're going to debate the question of 'To Dispose or not to Dispose', it might help if everyone including the audience, become a bit more familiar with the inner workings of DisposableWrapper, and the fact that any managed wrapper that represents a native object that derives from AcRxObject, must derive from DisposableWrapper, regardless of whether it must be disposed or not.




TheMaster

  • Guest
Re: Kean Walmsley on Dispose()
« Reply #5 on: August 23, 2012, 10:23:48 AM »
if you're not sure about the need to dispose something, just check its AutoDelete property. If it's false, then the odds are that you are either not supposed to delete it, or don't need to.

Does that mean this would be acceptable in all cases where you are deleting an object?
Code - C#: [Select]
  1. if ( MyObject.AutoDelete )
  2. {
  3.      MyObject.Delete();
  4. }

I have never understood the AutoDelete property and your description makes it seem counter-intuitive i.e. if AutoDelete is false it is automatically handled? It seems it should be the other way around unless I am missing something.

Some native objects should never be deleted when their managed wrapper is disposed, so this property tells the base class if it needs to delete the managed wrapper automatically. For example, if you call Dispose() on a Database wrapper for a database that's open in the editor, and the underlying AcDbDatabase was deleted, the result would be catastrophic, so this property is intended to ensure that could not happen.

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: Kean Walmsley on Dispose()
« Reply #6 on: August 23, 2012, 10:33:47 AM »
So, am I to understand that the AutoDelete property is really in reference to the underlying unmanaged object? i.e. if AutoDelete is false, the unmanaged object doesn't get deleted when the wrapper is disposed. This makes sense in that the unmanaged object is not automatically deleted when its wrapper is disposed.

However, doesn't that mean that the unmanaged object should be deleted? Will it result in memory leaks if it is not?
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Kean Walmsley on Dispose()
« Reply #7 on: August 23, 2012, 11:20:58 AM »
For a DBObject it checks Autodelete and pointer and if so calls DeleteUmanagedObject
 
Code - C#: [Select]
  1.  
  2.         ////    DisposableWrapper
  3.         public sealed override void Dispose()
  4.         {
  5.             this.Dispose(true);
  6.             GC.SuppressFinalize(this);
  7.         }
  8.  
  9.         ////    DisposableWrapper
  10.         protected virtual void Dispose([MarshalAs(UnmanagedType.U1)] bool flag)
  11.         {
  12.             if (flag)
  13.             {
  14.                 this.~DisposableWrapper();
  15.             }
  16.             else
  17.             {
  18.                 try
  19.                 {
  20.                     this.!DisposableWrapper();
  21.                 }
  22.                 finally
  23.                 {
  24.                     base.Finalize();
  25.                 }
  26.             }
  27.         }
  28.         ////    DisposableWrapper
  29.         private void ~DisposableWrapper()
  30.         {
  31.             this.!DisposableWrapper();
  32.         }
  33.         ////    DisposableWrapper
  34.         private void !DisposableWrapper()
  35.         {
  36.             if (this.m_bAutoDelete && this.m_imp != IntPtr.Zero)
  37.             {
  38.                 this.DeleteUnmanagedObject();
  39.             }
  40.             this.Detach();
  41.         }
  42.  
  43.  
  44.  
  45.         ////    DisposableWrapper
  46.         internal void Detach()
  47.         {
  48.             this.m_imp = IntPtr.Zero;
  49.             if (this.m_bAutoDelete)
  50.             {
  51.                 GC.SuppressFinalize(this);
  52.             }
  53.             this.m_bAutoDelete = false;
  54.             GC.KeepAlive(this);
  55.         }
  56.  
  57.         ////    DBObject
  58.         protected override void Dispose([MarshalAs(UnmanagedType.U1)] bool flag)
  59.         {
  60.             if (flag)
  61.             {
  62.                 try
  63.                 {
  64.                     return;
  65.                 }
  66.                 finally
  67.                 {
  68.                     base.Dispose(true);
  69.                 }
  70.             }
  71.             try
  72.             {
  73.                 this.!DBObject();
  74.             }
  75.             finally
  76.             {
  77.                 base.Dispose(false);
  78.             }
  79.         }
  80.         ////    DBObject
  81.         protected unsafe override void DeleteUnmanagedObject()
  82.         {
  83.             AcDbObject* impObj = this.GetImpObj();
  84.             AcDbObjectId acDbObjectId;
  85.             if (((*<Module>.AcDbObject.objectId(impObj, &acDbObjectId) == 0L) ? 1 : 0) != 0)
  86.             {
  87.                 if (impObj != null)
  88.                 {
  89.                     object arg_24_0 = calli(System.Void* modopt(System.Runtime.CompilerServices.CallConvCdecl)(System.IntPtr,System.UInt32), impObj, 1, *(*(long*)impObj));
  90.                 }
  91.             }
  92.             else
  93.             {
  94.                 int num = (int)<Module>.AcDbObject.close(this.GetImpObj());
  95.                 if (num != 0)
  96.                 {
  97.                     throw new Autodesk.AutoCAD.Runtime.Exception((ErrorStatus)num);
  98.                 }
  99.             }
  100.         }
  101.         ////    DBObject
  102.         public void Close()
  103.         {
  104.             int num = (int)<Module>.AcDbObject.close(this.GetImpObj());
  105.             if (num != 0)
  106.             {
  107.                 throw new Autodesk.AutoCAD.Runtime.Exception((ErrorStatus)num);
  108.             }
  109.             base.Detach();
  110.         }
  111.  

Kean

  • Newt
  • Posts: 48
Re: Kean Walmsley on Dispose()
« Reply #8 on: August 23, 2012, 12:35:01 PM »


This was a comment I just posted on Kean's blog, regarding his analysis on this subject.

Quote

Kean, this is more directed at Fenton's advice regarding Dispose(), but neither his nor any of your posts on this topic so much as graze one important aspect of the question, which is the DisposableWrapper's AutoDelete property.

If this property is false, the wrapped native object is not deleted when its managed wrapper is disposed, and disposing a managed wrapper whose AutoDelete property is false, is both pointless and a source of code obfuscation. 

And, if one is going to check the value of this property and use it as a guide for deciding to Dispose the managed wrapper, then one must remember that the managed wrapper can change its value depending on certain conditions. For example, the Database managed wrapper sets this property to true only when the wrapped AcDbDabase was created via a call to ReadDwgFile(). For databases that are open in the drawing editor, the value of AutoDelete is false.

I think it's a bit silly for everyone to be debating this issue when the value of that property literally and definitively answers that question for many (but not all) objects, don't you agree?

If we're going to debate the question of 'To Dispose or not to Dispose', it might help if everyone including the audience, become a bit more familiar with the inner workings of DisposableWrapper, and the fact that any managed wrapper that represents a native object that derives from AcRxObject, must derive from DisposableWrapper, regardless of whether it must be disposed or not.


Strange - I didn't get that comment through.

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: Kean Walmsley on Dispose()
« Reply #9 on: August 23, 2012, 04:34:21 PM »
... and I am still as confused as I was before ...

AutoDelete = false means the underlying item isn't deleted when the wrapper is disposed, but disposing when AutoDelete = false is unnecessary and disposing when AutoDelete is true means the underlying object is disposed when the wrapper is disposed so disposing the wrapper automatically deletes the underlying unmanaged object.

which brings me full circle to what the heck does it mean? Dispose or not? ... and how can we effectively use AutoDelete to determine if we should dispose of the managed wrapper?
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

TheMaster

  • Guest
Re: Kean Walmsley on Dispose()
« Reply #10 on: August 23, 2012, 05:51:41 PM »
So, am I to understand that the AutoDelete property is really in reference to the underlying unmanaged object? i.e. if AutoDelete is false, the unmanaged object doesn't get deleted when the wrapper is disposed. This makes sense in that the unmanaged object is not automatically deleted when its wrapper is disposed.

However, doesn't that mean that the unmanaged object should be deleted? Will it result in memory leaks if it is not?

Some native objects are part of an aggregation, which are usually exposed and managed by some other native 'owner' object.  For example, the TransactionManager is a wrapper for an AcDbTransctionManager. The native AcDbTrasactionManager object is created and deleted by the native AcDbDatabase that uses it, so it should never be deleted by anyone else, including managed wrappers. If you check, you should see that a TransactionManager's AutoDelete property is false, making disposal pointless.

I wasn't suggesting that one should write code that checks the AutoDelete property at runtime and disposes the object only if it's true because that results in even greater code obfuscation than just calling Dispose(). I was suggesting that one can check to see if the type(s) of managed wrappers their code works with always have their AutoDelete property set to false. If so, then it is probably better to not bother disposing them.


Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: Kean Walmsley on Dispose()
« Reply #11 on: August 23, 2012, 08:01:34 PM »
That makes more sense ... now the problem becomes understanding which of these items should be disposed always and which should be disposed occasionally and which should never be disposed.

Maybe I should have went into medicine .. at least then my clients would understand that everything I do is practice ...
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Kean Walmsley on Dispose()
« Reply #12 on: August 23, 2012, 10:02:52 PM »


This was a comment I just posted on Kean's blog, regarding his analysis on this subject.

Quote

< .. >

If we're going to debate the question of 'To Dispose or not to Dispose', it might help if everyone including the audience, become a bit more familiar with the inner workings of DisposableWrapper, and the fact that any managed wrapper that represents a native object that derives from AcRxObject, must derive from DisposableWrapper, regardless of whether it must be disposed or not.



Tony,
[for clarity]
I assume the 'must' should be read as 'does'

Regards
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.

TheMaster

  • Guest
Re: Kean Walmsley on Dispose()
« Reply #13 on: August 23, 2012, 10:03:39 PM »


This was a comment I just posted on Kean's blog, regarding his analysis on this subject.

Quote

Kean, this is more directed at Fenton's advice regarding Dispose(), but neither his nor any of your posts on this topic so much as graze one important aspect of the question, which is the DisposableWrapper's AutoDelete property.

If this property is false, the wrapped native object is not deleted when its managed wrapper is disposed, and disposing a managed wrapper whose AutoDelete property is false, is both pointless and a source of code obfuscation. 

And, if one is going to check the value of this property and use it as a guide for deciding to Dispose the managed wrapper, then one must remember that the managed wrapper can change its value depending on certain conditions. For example, the Database managed wrapper sets this property to true only when the wrapped AcDbDabase was created via a call to ReadDwgFile(). For databases that are open in the drawing editor, the value of AutoDelete is false.

I think it's a bit silly for everyone to be debating this issue when the value of that property literally and definitively answers that question for many (but not all) objects, don't you agree?

If we're going to debate the question of 'To Dispose or not to Dispose', it might help if everyone including the audience, become a bit more familiar with the inner workings of DisposableWrapper, and the fact that any managed wrapper that represents a native object that derives from AcRxObject, must derive from DisposableWrapper, regardless of whether it must be disposed or not.


Strange - I didn't get that comment through.

Sorry, I just brought that window forward and noticed some message about a 'timeout'.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Kean Walmsley on Dispose()
« Reply #14 on: August 24, 2012, 12:29:17 AM »

Tony, et al

Regarding autoDelete :
Under what circumstances would the autoDelete property be false ?

The constructors for (say) a line sets the property to true through the base class.

ie :

Code - C#: [Select]
  1.  public unsafe Line(Point3d pointer1, Point3d pointer2) : base(ptr, true)
  2. {
  3.     AcDbLine* modopt(IsConst) modopt(IsConst) linePtr;
  4.     void* voidPtr = AcHeapOperators.allocRawMem(0x18L);
  5.     AcDbLine* linePtr2 = (AcDbLine*) voidPtr;
  6.     try
  7.     {
  8.         linePtr = AcDbLine.{ctor}((AcDbLine* modopt(IsConst) modopt(IsConst)) voidPtr,
  9.                                           (AcGePoint3d modopt(IsConst)* modopt(IsImplicitlyDereferenced)) ((long) &pointer1),
  10.                                           (AcGePoint3d modopt(IsConst)* modopt(IsImplicitlyDereferenced)) ((long) &pointer2));
  11.     }
  12.     fault
  13.     {
  14.         ___CxxCallUnwindDelDtor(AcHeapOperators.delete, (void*) linePtr2);
  15.     }
  16.     IntPtr ptr = (IntPtr) linePtr;
  17. }
  18.  
  19.  
  20.  

The Curve base to Line :
Code - C#: [Select]
  1. protected internal Curve(IntPtr unmanagedObjPtr,
  2.        [MarshalAs(UnmanagedType.U1)] bool autoDelete) : base(unmanagedObjPtr, autoDelete)
  3. {
  4. }
  5.  

with this being the dependency chain

Code - C#: [Select]
  1. [TypeDescriptionProvider("Autodesk.AutoCAD.ComponentModel.TypeDescriptionProvider`1[[Autodesk.AutoCAD.DatabaseServices.Line, acdbmgd]], acdbmgd"), Wrapper("AcDbLine")]
  2. public class Line : Curve
  3. {
  4.     // Methods
  5.     public Line();
  6.     public Line(Point3d pointer1, Point3d pointer2);
  7.     protected internal Line(IntPtr unmanagedObjPtr, [MarshalAs(UnmanagedType.U1)] bool autoDelete);
  8.     internal unsafe AcDbLine* GetImpObj();
  9.  
  10.     //<..>
  11. }
  12.  
  13. [TypeDescriptionProvider("Autodesk.AutoCAD.ComponentModel.TypeDescriptionProvider`1[[Autodesk.AutoCAD.DatabaseServices.Curve, acdbmgd]], acdbmgd"), Wrapper("AcDbCurve")]
  14. public abstract class Curve : Entity
  15. {
  16.     // Methods
  17.     protected internal Curve(IntPtr unmanagedObjPtr, [MarshalAs(UnmanagedType.U1)] bool autoDelete);
  18.     public static Curve CreateFromGeCurve(Curve3d geCurve);
  19.     public static Curve CreateFromGeCurve(Curve3d geCurve, Tolerance tolerance);
  20.     public static Curve CreateFromGeCurve(Curve3d geCurve, Vector3d __unnamed001);
  21.     public static Curve CreateFromGeCurve(Curve3d geCurve, Vector3d __unnamed001, Tolerance tolerance);
  22.      //<..>
  23. }
  24.  
  25. [Wrapper("AcDbObject"), TypeDescriptionProvider("Autodesk.AutoCAD.ComponentModel.TypeDescriptionProvider`1[[Autodesk.AutoCAD.DatabaseServices.DBObject, acdbmgd]], acdbmgd")]
  26. public abstract class DBObject : Drawable
  27. {
  28.     //<..>
  29.  
  30.     // Methods
  31.     private void !DBObject();
  32.     static DBObject();
  33.     protected internal DBObject(IntPtr unmanagedObjPtr, [MarshalAs(UnmanagedType.U1)] bool autoDelete);
  34.     //<..>
  35. }
  36.  
  37. [Wrapper("AcGiDrawable")]
  38. public abstract class Drawable : RXObject
  39. {
  40.     // Methods
  41.     protected internal Drawable(IntPtr unmanagedPointer, [MarshalAs(UnmanagedType.U1)] bool autoDelete);
  42.     //<..>
  43. }
  44.  
  45. [Wrapper("AcRxObject")]
  46. public abstract class RXObject : DisposableWrapper, ICloneable
  47. {
  48.     // Methods
  49.     protected internal RXObject(IntPtr unmanagedPointer, [MarshalAs(UnmanagedType.U1)] bool autoDelete);
  50.     //<..>
  51. }
  52.  
  53. public abstract class DisposableWrapper : MarshalByRefObject, IDisposable
  54. {
  55.     //<..>
  56.     // Methods
  57.     private void !DisposableWrapper();
  58.     protected DisposableWrapper();
  59.     [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
  60.     protected DisposableWrapper(IntPtr unmanagedPointer, [MarshalAs(UnmanagedType.U1)] bool autoDelete);
  61.     private void ~DisposableWrapper();
  62.     internal void Attach(IntPtr unmanagedPointer, [MarshalAs(UnmanagedType.U1)] bool autoDelete);
  63.     [EditorBrowsable(EditorBrowsableState.Advanced), SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
  64.     public static DisposableWrapper Create(Type type, IntPtr unmanagedPointer, [MarshalAs(UnmanagedType.U1)] bool autoDelete);
  65.     //<..>
  66. }
  67.  
  68. [Serializable, ComVisible(true)]
  69. public abstract class MarshalByRefObject
  70. {
  71.     //<..>
  72.  
  73.     // Methods
  74.      //<..>
  75.  
  76.  
  77. [ComVisible(true)]
  78. public interface IDisposable
  79. {
  80.     // Methods
  81.     void Dispose();
  82. }
  83.  
  84.  


Just an aside.
It pleases me immensely to see the level of discussion on these subjects.
Thanks to all who are participating and attempting to clear up concepts that have been in dispute for years.

Regards,
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.