I must have missed this reply, and saw it just now when I went to get the link to this thread.
See below:
If there's only a limited set of specific types that my method can use (all of which implement IEnumerable), then I'd write an overload for each.
This condition isn't met when we consider that my method can use any instance of IEnumerable<ObjectId> too.
Your method isn't using IEnumerable<ObjectId>, it's using IEnumerable and IEnumerator. IEnumerator.Current returns the value boxed in a System.Object. While it's true that foreach() also uses IEnumerator on types that implement only IEnumerable, the only overload of GetObjects<T>() that I have here that uses foreach() is the one targeting BlockTableRecord, SymbolTable, and IEnumerable<ObjectId>, and the latter will test its argument to see if it is an array and in that case, will delegate to the overload that takes an array of ObjectId[], which uses the array indexer to iterate over the items (because it's faster).
I also have an overload of GetObjects<T> that takes an IEnumerable<ObjectId>, and it is by-far them most complicated of all the overloads, because it tests the argument to see if it is an array of ObjectId[] and uses another overload that is optimized for arrays. So, I think I have all the bases covered with my overloads.
Ditto for ObjectIdCollection. Here is a reduced version of one of my implementations of GetObjects<T> for ObjectIdCollection:
public static IEnumerable<T> GetObjects<T>( this ObjectIdCollection ids )
{
RXClass rxclass
= RXClass
.GetClass( typeof( T
) ); int cnt = ids.Count;
for( int i = 0; i < cnt; i++ )
{
ObjectId id = ids[i];
if( id.ObjectClass.IsDerivedFrom( rxclass ) )
yield return (T) id.GetObject( OpenMode.ForRead, false, false );
}
}
And, I'm not sure what this has do with a method called "GetObjects()" showing up in the Intellisense dropdown list for an instance of
anything that implements IEnumerable, and I have a major issue with that.
There really is no excuse for not providing overloads targeting the handful of types that expose a sequence of ObjectIds, especially considering that each also has other distinct variations (like supporting erased objects) that don't apply all IEnumerables. For example, SymbolTable and BlockTableRecord both support the IncludingErased property, so you can't write a single one-size-fits-all version of GetObjects<T> that accommodates that option, or other parameters that do not apply to any IEnumerable, without introducing even more complexity than multiple overloads entails.
I have to concede that contrary to gut feeling the number of types which implement IEnumerable (ICollection, IList) only non-generically is indeed limited. Over the complete API of a typical AutoCAD vertical there may be a handful of candidates, AecArchMgd for example seems to have none.
From acdbmgd:
Autodesk.AutoCAD.DatabaseServices.AttributeCollection
Autodesk.AutoCAD.DatabaseServices.BlockTableRecord
Autodesk.AutoCAD.DatabaseServices.ObjectIdCollection
Autodesk.AutoCAD.DatabaseServices.SymbolTable
Autodesk.AutoCAD.DatabaseServices.SymbolTableRecord
Autodesk.AutoCAD.LayerManager.LayerCollection
From aecbasemgd:
Autodesk.Aec.DatabaseServices.ClassificationCollection
Autodesk.Aec.DatabaseServices.DisplayRepresentationIdCollection
Autodesk.Aec.DatabaseServices.ObjectIdCollection
The underlying purpose of the various extension methods I showed is to simplify as much as possible, application-level code.
In my opinion, you optimize and therefore complicate as much as possible. The optimizations can be deemed premature; in the sense of premature in an application's life-cycle.
Apparently you didn't get the meaning of 'application-level' code. The complicated library code is what makes it possible for me to write application-level code that is far less complicated. By application-level code, I mean implementation of simple commands and so forth, that one might otherwise write in LISP. But, in fact, the API's I showed a small glimpse of here, makes writing simple commands easier in .NET than they would be if written in LISP.
I usually optimize (and complicate) library code that is called often but rarely if ever modified, making its complexity irrelevant in the everyday use of it. The whole point of making the library code complicated is to un-complicate and simplify the application-level code that uses the library code.
I'm pretty confident that every single of them will result in a measurable if not noticeable performance increase. There's nothing wrong with having a well-tuned and well-tested toolbox at one's disposal when aiming for a commercial release. But the majority of uses are either to get the job done no questions asked, or to prototype, or to explain and explore specific concepts.
In a post in another thread that I just wrote, I was too lazy to write a code example that uses only native APIs to do something relatively simple in an example command implementation. So, I used the same APIs that I use routinely in my real coding to get the job done more quickly, no questions asked.
It is that complicated API with all of its complicated overloads of GetObjects<T>() that allows me to write much simpler application-level code, much faster and with far fewer errors. As far as a single one-size-fits-all version of GetObjects() goes, that doesn't work because it can't easily provide for options for some types, like including erased objects, etc.