I added code that will (correctly) chose the most derived property/field
when a conflict exists between the parent and child.
According to Microsoft, there is no guarantee of the order that members
will be returned, so I had to determine the members distance from the
object's type down the inheritance hierarchy and pick the closest.
I have been slowly working toward supporting variables that can be
declared/updated during output generation. This code also cleans up the
code for searching within a scope.
Since there weren't consistent rules for when to include newlines, I
decided to make an explicit tag (similar to HTML's <br /> tag). This can
have a dramatic impact on your existing code (unless it is just HTML).
RegexOptions.Compiled does not seem to improve performance and actually
is a bottleneck in most cases. I am removing it for the time being. I
may add a flag to the FormatCompiler if it is needed in the future.
I was not removing context when I was leaving a tag. This caused the
context to grow indefinitely, which is not a valid representation of
where the placeholder was located in the template.
It could be useful to know the context when discovering a placeholder.
I also renamed MissingKeyEventArgs to KeyNotFoundEventArgs.
I created a new event KeyFoundEventArgs.
It could be useful to track which placeholders were found when parsing
the template. This event will allow keys to be mapped to different keys,
and support changing alignment and formatting.
A request was made to provide the original key as well as the member
that was not found. In compound keys {{Customer.Address.ZipCode}}, any
of the names could be invalid, but knowing the fully-qualified name is
useful for error handling.
I also detected a bug where the code wasn't handling the case that a
sub-key didn't exist. This needs to be handled using the KeyNotFound
event.
A request was made to allow missing keys to be handled in a custom
manner. I created an event that can be registered with the Generator
instances.
I also fixed a deployment issue causing debug versions of the library to
be packaged and released to NuGet. This should boost performance
considerably.
The way the code was implemented before, each block of text was
generating a string which was then being added to a StringBuilder. This
only improved performance within a block itself. Needing to then copy
the results of that builder into the parent tag's builder was wasteful.
Now, a single TextWriter is used for all tags. If a block needs to be
processed after-the-fact, the tag can indicate that it wants to provide
a new text writer and that it wants to consolidate the text.
This is the first step towards supporting custom tags. There are
wrinkles I need to work out, since I'm not 100% sure what the finished
code will look like.
This is the code almost verbatim from the NList project. This project is
due for a major overhaul, but I don't know the order I will be breaking
out NList in the upcoming weeks.