Click here to Skip to main content
15,888,113 members
Please Sign up or sign in to vote.
2.50/5 (2 votes)
See more:
I've got the following code for a basic 2d point class:

C#
public class PointXY : Point2D
    {
        private float x, y;

        public static readonly PointXY ORIGIN = new PointXY();

        public PointXY()
        {  }

        public PointXY(float x, float y)
        {
            Set(x, y);
        }

        public float X
        {
            get { return x; }
            set { x = value; }
        }

        public float Y
        {
            get { return y; }
            set { y = value; }
        }
}


So I want the values of ORIGIN x and y to stay constant at x=0, y=0. But from the main console, I can still type :

C#
PointXY a = PointXY.ORIGIN; // ok
a.X = 4; // shouldn't be ok 


or even just:

C#
PointXY.ORIGIN.X = 4; // shouldn't be ok


From a purely mathematical sense I shouldn't be able to change the values of x and y of the ORIGIN to be something other than its value of 0. How do I do this in C#? Am I missing something here?
Posted
Comments
Wonde Tadesse 25-Jan-16 20:21pm    
If you don't want change x and y, then don't expose them as property setter. i.e remove the property setter while keeping the getter.
Philippe Mori 25-Jan-16 20:44pm    
C# is not C++. In C#, const is mainly used for predefined type constants.
Sergey Alexandrovich Kryukov 25-Jan-16 22:28pm    
You don't understand readonly. The field is really read-only. But you expect that its copy would be read-only, which is absurd. First of all, why?
You use read-only field to initialize another variable/member, what's wrong with it?
If you need the read-only copy, create another read-only member and initialize it with your read-only field...
—SA

One way to do it is to derive from an interface with only read-only members. And you change the type of the "constant" to be the type of that interface instead.

C#
interface IPointXY
{
  float X { get; }
  float Y { get; }
}

public class PointXY : Point2D, IPointXY 
{
  public static readonly IPointXY ORIGIN = new PointXY();
  //.... Other stuff as before
}

You might even decide to use another class for the implementation of those constant if you have other functions that could modify the object in the main class.

Note that you will have to use the interface instead of the class in your code.

The other option is to never allows to modify a point after it has been created. This is the options use by some .NET type like string, DateTime and so on.
 
Share this answer
 
Comments
Sergey Alexandrovich Kryukov 25-Jan-16 22:30pm    
5ed. See also my comment to the question.
—SA
I use private setters for the properties:

C#
public class Point
{
  public int X { get ; private set ; }
  public int Y { get ; private set ; }

  public Point
  ( int X
  , int Y 
  )
  {
    this.X = X ;
    this.Y = Y ;
  } 

  public Point() : this ( 0 , 0 ){}

  public Point ( Point Source ) : this ( Source.X , Source.Y ){}
}
 
Share this answer
 
Comments
johnstda 25-Jan-16 23:35pm    
I think this might work, because most of the changes are down with its own methods or overloaded operators anyway.
While Java has a 'Point2D structure, to my knowledge, C# does not.

C# has 'Point, and 'PointF. 'PointF is sealed, so you can't inherit from it. However, assuming you want to be able to handle both integer C# Point, and other numeric-Type C# Types, you can do something like this:
C#
public class PointXY<T> where T :
    // see Jon Skeet:
    // http://stackoverflow.com/a/7690962/133321
    struct,
    IComparable,
    IFormattable,
    IConvertible,
    IComparable<T>,
    IEquatable<T>
{
    private static PointXY<T> _origin;
    public static PointXY<T> Origin
    {
        private set { _origin = value; }
        get { return _origin; }
    }

    // must have parameterless 'ctor
    public PointXY()
    {
    }

    public PointXY(T ox, T oy)
    {
        if (Origin == null)
        {
            Origin = new PointXY<T>();
            Origin.X = ox;
            Origin.Y = oy;
        }
    }

    private T _x;
    public T X
    {
        get { return _x; }
        set { _x = value; }
    }

    private T _y;
    public T Y
    {
        get { return _y; }
        set { _y = value; }
    }
}
Consider the result of this test, however:
C#
PointXY<int> p1 = new PointXY<int>(32, 99);
PointXY<int> p1a = new PointXY<int>(132, 199);
PointXY<double> p2 = new PointXY<double>(23.4, 32.4);

Console.WriteLine("{0} {1}, {2}", p1.Origin, p1.Origin.X, p1.Origin.Y);
Console.WriteLine("{0} {1}, {2}", p1a.Origin, p1a.Origin.X, p1a.Origin.Y);      
Console.WriteLine("{0} {1}, {2}", p2.Origin, p2.Origin.X, p2.Origin.Y);

// in Console:
PointXY`1[System.Int32] 32, 99
PointXY`1[System.Int32] 32, 99
PointXY`1[System.Double] 23.4, 32.4</double></double></int></int></int></int>
You'll note that in this code, once you've set the 'Origin for one specific Type, then you can't reset it. That may not be what you want, but it would be easy enough to add some kind of over-ride to let the 'Origin be reset based on certain criteria.
 
Share this answer
 
v5

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900