do anything associated with creating, reading, or otherwise processing
an invoice to a customer. It is an uber-DAO object that combines the
business logic and DAO layers. The invoice it handles can have one to
many lines. The most logical implementation is an Invoice object with
an array of InvoiceLine objects. We of course want to prevent Joe
Programmer from directly manipulating the array. In our case Joe should
be able to get a reference to an object in the array to access *its*
members (item ID, quantity, unit price), but should not be able to set
an invoice line index to a new object reference. So, we need to hide it
behind a property accessor.
>From what I understand, doing the following in C# will not work://within Invoice class declaration
private InvoiceLine[] _lines;
public InvoiceLine Line[int index]
{
get{
//TODO: create a new object and append it to the array if the
index is beyond the upper bound
return _lines[index];
}
}
Instead, as I understand it, the array will be wrapped in an indexer
object. I probably won't be dealing with interfaces; for one,
implementing IList AFAIK requires me to implement the Add() function,
which I don't want Joe Programmer to have access to. So the above code
would instead be replaced with something like:
private class LineIndexer
{
private InvoiceLine[] _lines;
public LineIndexer this[int index]
{
get{
//TODO: create a new object instance and append if the index
is out-of-bounds
return _lines[index];
}
}
}
//within Invoice class declaration
private LineIndexer _lines;
public LineIndexer Line
{
get{
return _lines;
}
}
Joe Programmer could then code a static line to set a property, similar
to:
myInvoice.Line[1].ItemID.Value = "My New Item 001";
(footnote: ItemID is itself a read-only property accessor for a nested
object, allowing us to encapsulate field information used for
validation and display, like type, length and whether the field is
required)
So, having figured out all that, the question is, how does this affect
being able to dynamically parse through a property identifier like the
one above when using reflection? To work with a property four or five
levels down, I start with a string identifying the "fully qualified"
property in dot notation. I then parse this string dot by dot to get
each member, which is always a property, and get the value of that
property which gives me the next class reference, and repeat. However,
to the best of my knowledge when I get to "Line[1]", I will not get an
InvoiceLine object by setting up a PropertyInfo object for Line and
passing an index as the parameter.
Or will I?
I can't test this right now, but I am thinking that, if I parse out an
index (the code already looks for [x] in the identifier string and
returns x as int), I'll need to know that there's an extra step: get
the LineIndexer reference, *then* get the actual line object from
LineIndexer by using the index I parsed out.
This method needs to be as elegant and fast as possible, it needs to
work flawlessly with reflection techniques (the algorithm doing all the
parsing can know in general how our business objects are put together,
but it cannot know at compile time which business object type it will
be working with), it needs to be able to deal with multiple indexed
properties in a chain (an InvoiceLine would for instance implement an
array of InvoiceLineJob objects that show which project a contractor
spent the listed time and materiel on), and future generations need to
understand what the flying flip I'm doing (assume I'm commenting the
code like a tutorial). It doesn't, at this time, have to work with
multi-dimensional arrays. I heard that the concept of indexed
properties is more transparently implemented in VB.Net, but we're
trying to avoid unnecessary complexity, and programming different
objects in different languages does just that.