private array member still public...?

  • Thread starter Thread starter bern11
  • Start date Start date
B

bern11

I have a class with a 3 point array which I want to protect through
encapsulation. Unfortunately, the following does not do what I want:
private PointF[] vtx = new PointF[3];
public PointF[] Vtx
{
get { return vtx; }
set
{
vtx = value;
SetBounds();
}
}

I want to call the 'set' member whenever an individual array element is
called. As it is, this statement:
myObject.Vtx[0] = 10;
does not call the 'set' accessor, even though a statement such as this
calls the 'get' accessor:
x = myObject.Vtx[0];

So, how do I encapsulate access to individual members of a member array?

In hindsight, it is clear that my declaration is screwed up, since the
'set' declaration would only work if value were a 3 point array, not a
single value. But, how to fix it?
 
PS - indexers don't seem to work for me. This is an array member in a
class that has to exectute another member function. If I nest it so the
indexer works, I can't reference the class function SetBounds....
 
[...]
I want to call the 'set' member whenever an individual array element is
called. As it is, this statement:
myObject.Vtx[0] = 10;
does not call the 'set' accessor, even though a statement such as this
calls the 'get' accessor:
x = myObject.Vtx[0];

So, how do I encapsulate access to individual members of a member array?

If I understand your goal correctly, you can't really do exactly what you
want while preserving the PointF[] semantics. But you can get very close.

In C#, you can create an indexed property:

PointF this[int ipt]
{
get { return vtx[ipt]; }
set { vtx[ipt] = value; }
}

See: http://msdn2.microsoft.com/en-us/library/2549tw02(VS.80).aspx

Using that syntax, you can either make your main class have the indexer,
or more likely you'll want to create a specific class to hold the vertex
array, which has an indexed property like that, and which you expose as a
regular property in the main class.

The former is simpler, but creates what IMHO is an awkward syntax if the
main class isn't itself something that is semantically an abstracted list
of points. The latter is more complicated, but can more correctly
represent the intent behind the design, assuming this list of points is
but one of many things the main class contains and exposes.

Either way, it allows you to completely hide the underlying implementation
and require the client of your class to access the elements through your
own indexer, giving you the opportunity to include whatever specific
restrictions you like. Of course, even if your only goal is to hide the
underlying array, it works fine for that too.
In hindsight, it is clear that my declaration is screwed up, since the
'set' declaration would only work if value were a 3 point array, not a
single value. But, how to fix it?

How to fix what? The two problems are not really related. If you are
asking a second question, regarding how to ensure that the array being
assigned is compatible with the intent, in your sample code you could look
at the Length property of "value" before assigning it:

set
{
if (value.Length != 3)
{
throw new InvalidArgumentException("array must have exactly3
elements");
}

vtx = value;
SetBounds();
}

Pete
 
PS - indexers don't seem to work for me. This is an array member in a
class that has to exectute another member function. If I nest it so the
indexer works, I can't reference the class function SetBounds....

Why not? As long as the nested class keeps a reference to the containing
class, it should be able to call whatever method you need it to.

Alternatively (and probably a better design anyway) would be for the
nested class to declare an event that's raised when the indexer's setter
is called. Then the containing class can just subscribe to it. Much more
general-purpose, and would allow the subordinate class to not even be a
nested class in case you wanted to use it elsewhere.

Pete
 
Back
Top