views:

171

answers:

4

I have a a polygon class which stores a list of Microsoft.Xna.Framework.Vector2 as the vertices of the polygon. Once the polygon is created, I'd like other classes to be able to read the position of the vertices, but not change them.

I am currently exposing the vertices through this field:

/// <summary>
/// Gets the vertices stored for this polygon.
/// </summary>
public List<Vector2> Vertices
{
    get { return _vertices; }
}
List<Vector2> _vertices;

However you can change any vertex using code like:

Polygon1.Vertices[0] = new Vector2(0, 0);

or

Polygon1.Vertices[0].X = 0;

How can I limit other classes to be able to only read the properties of these vertices, and not be able to set a new one to my List? The only thing I can think of is to pass a copy to classes that request it.

Note that Vector2 is a struct that is part of the XNA framework and I cannot change it.

Thanks.

+6  A: 

Have a readonly interface on your type (however since this is built in type), and pass out a version in a ReadOnlyCollection is for.

public ReadOnlyCollection<IReadOnlyVector2> Vertices
{
    get { return (from v in _vertices 
                  select new DerivedVector2 { WrappedVector2 = v })
                 .Cast<IReadOnlyVector2>().ToList().AsReadOnly(); 
     }
}
List<Vector2> _vertices;

interface IReadOnlyVector2 {
 .. only RO getters and no setters
}

class DerivedVector2 : IReadOnlyVector2{
    public Vector2 WrappedVector2 { get; internal set;} 
.
.
.

}

Preet Sangha
calling `_vertices.AsReadOnly()` is usually preferred.
Adam Robinson
Didn't know about that! Thank you
Preet Sangha
If you're calling `Cast()`, you could actually just expose `IEnumerable<IReadOnlyVector2>`, assuming that interface has the functionality you need. The `Cast` function effectively isolates the original list from the consuming code (as do any of the other transformative functions on `Enumerable`).
Adam Robinson
A: 

Do as the XNA Framework often does:

private List<Vector2> myVectors = new List<Vector2>();

public Vector2[] Vertices { get { return myVectors.ToArray(); } }
Krisc
A: 

Just wanted to offer a variation on Preets answer.

public IEnumerable<IReadOnlyVector2> Vertices
{
    get
    {
        return from v in _vertices 
               select (IReadOnlyVector2)new DerivedVector2(v);
    }
}

Returning an IEnumerable<> is inherently read-only since clients can only enumerate, not change. Also, the simplified LINQ expression removes the three additional steps which imo is superfluous.

It is worth mentioning the effect of .ToList(). It will create a new instance of List<> and copy all vectors into that list. A side effect of this is that clients storing the reference will have a list that is effectively out of sync with the original. On the other hand, if we return the LINQ expression directly, enumerating the reference returned will always enumerate the internal list.

Peter Lillevold
A: 

Yet another variation, using yield:

List<Vector2> _vertices;
public IEnumerable<Vector2> Vertices
{
    get
    {
        foreach (Vector2 vec in _vertices)
            yield return vec;
    }
}

Although i'd probably say Krisc's answer is best...

Next to _vertices.AsReadOnly() of course :D

YellPika