Welcome to part 7 of LINQ and the AutoCAD .NET API. In the last post we extended the GeneralHelper class to support write operations. In today's post we have a look on how we can add a convenient way to create new AutoCAD objects and add them to the database. And be prepared, there's a lot of code in this post.
Object creation
Let's start with an example. The standard procedure to create a new layer using the .NET API goes something like this:
This is pretty much what we can find in most of the AutoCAD .NET tutorials out there. In this blog post series our overall goal is to create an API that simplifies working with the AutoCAD API. Now, can we find a neat way to integrate object creation into our GeneralHelper? What could the call to the GeneralHelper class look like? Something like this would be nice:
This would be a more intuitive API: the helper object as our entry point (we should find a better name for the GeneralHelper btw), the property Layers to access all the layer dependent stuff, two methods to validate the layer name and a Create method to actually create the new layer.
Let's go back and look at the current implementation of the GeneralHelper. We only look at the parts we need for the layers, the rest is cut out:
So IEnumerable<LayerTableRecord> is the type of our Layers property. Since we want to have the Create method as a member of the Layers property's type, we could create a class called - say - LayerContainer that implements IEnumerable<LayerTableRecord>. Let's do this:
OK, two new things here. We have the LayerContainer class that implements IEnumerable<LayerTableRecord> and we changed the type of the Layers property to LayerContainer (the unnecessary parts in the GeneralHelper class are again left out).
We didn't break anything with this change, everything works like before. And now we can easily add the Create method and the validation methods to the LayerContainer class:
Looks good! Now the code in listing 2 works as expected.
Let's refactor
It's time for some refactoring. Is the functionality in the LayerContainer class applicable to other AutoCAD classes? Can we find an abstract base class that encapsualtes the common behaviour?
Let's see...
LayerTable is derived from SymbolTable, LayerTableRecord form SymbolTableRecord. It seems that all tables are derved from SymbolTable and the table records are derived from SymbolTableRecord. So we could make an abstract base class that represents a SymbolTable and works with any class that is derived from SymbolTableRecord. And we could pass the actual derived type as a type parameter to work with the "real" SymbolTableRecord type. Let's give it a try:
We replaced everything that was specific to LayerTableRecord stuff with the generic type T. Creating a new item has been moved to a protected abstract method called CreateItem that returns the new item. Hence the creation of a new item is handled by the derived class.
So, our LayerContainer has been shrunk to only a few lines of code. We just call the base class constructor and we implement the CreateNew method, and that's it:
The same pattern is now applicable to all classes that are derived from SymbolTableLayer, like BlockTableRecord for instance:
If we do this for all classes that are derived from SymbolTableLayer, our GeneralHelper now looks like this:
Wrapping up
How did we improve the GeneralHelper class? We found a nice way to hide the complexity of creating new AutoCAD objects behind our API.
Behind the scenes we were able to make the creation code reusable by putting it into a base class, so the only thing that has to be implemented by a derived class is creating and returning a new object in the CreateItem method. The validation code is the same for all implementers, so it is implemented in the base class.
What is still left is to further refactor the GeneralHelper class to use the creation code not only for tables, but for dictionaries as well. So in the next post we'll do some refactoring.