views:

153

answers:

5

Hey there,

i bumped the other day into a little problem regarding C#'s properties.

Let's say i do have this setup:

public class Point
{
 public float X;
 public float Y;
}

public class Control
{
 protected Point m_Position = new Point();

 public Point Position
 {
  get { return m_Position; }
  set 
  { 
    m_Position = value; }
    // reorganize internal structure..
    reorganize();
  }

  protected reorganize()
  {
   // do some stuff
  }
}

This is all fine, but when it comes to usage, i could write something like:

Control myControl = new Control();
myControl.Position.X = 1.0f;

The thing is, my Control class wont recognize that the Position has been changed because set hasn't been called.

So i guess my question is, is there a way to make Control aware of any Position changes?

Thanks in advance!

Mfg Imp

A: 

This should fix it! I have added a line into your getter that tests to see if the point is null and if it is instantiate it before returning.

public class Point
{
 public float X;
 public float Y;
}

public class Control
{
 protected Point m_Position = new Point();

 public Point Position
 {
  get 
  { 
      if (m_Position == null) m_Position = new Point();
      return m_Position; 
  }
  set 
  { 
    m_Position = value; 
    // reorganize internal structure..
    reorganize();
  }

  }

  protected reorganize()
  {
   // do some stuff
  }
}

HTH

OneSHOT
If people are going to down vote at least post a comment to provide a reason! The above code will directly solve the OP's problem and allow the code to work as per the OP's example.
OneSHOT
Why? This clearly won't fix the problem he's having and why check for null if m_Position is initialized when creating the control
PoweRoy
I didn't downvote, but it won't solve the OPs problem, because as he already mentioned, the setter will never be called, only the getter.
frenetisch applaudierend
No it will not solve the problem. The real problem is that the setter is not called in his use case.
klausbyskov
@OneSHOT : The OP problem is to make `Control` object aware of changes made to its `Point` property (ie changing `Point.X`). Your solution does not fix this.
Thibault Falise
I can't speak for the downvoters, but your solution doesn't address the primary problem of the class knowing when the values of the `Point` object returned by the `Position` property are changed. Please re-read the question.
Programming Hero
Seems I misread the question, Apologies!
OneSHOT
Well the solution with the callback per delegate is the most obvious one, but it does have some memory drawbacks and unnecessary structural overhead.The solution of exposing X and Y directly by Controls Interface is ok I think but then I have to get rid of the get Position property.Making it a struct would also work but comes down to the same solution making X, Y immutable within the Point class which i want prevent if possible.I really wonder why C# does not implement this in the first place..
Impz0r
I really start to wonder why c# does not implement it in the first place. I mean what it has to do is:1) Create an temporary object of that Typ, passing the original Member to the constructor, which implies that the type do has an copy constructor.2) Give the temporary object back3) Let the temporary object being altered4) Push back this temporary object to the setter5) Be done with it...Do you think its worth present this suggestion to the c# committee?
Impz0r
A: 

You could make public class Point a public struct Point. This way, the compiler will force you to write

myControl.Position = new Point() { X = 1.0f, Y = myControl.Position.Y; }

and the property setter is called.

Danvil
Well this comes down to the solution Tom Cabanski posted, making Point immutable. This is most likely the "best" way to achive more control. Point is, its kind of unflexable. I really wonder why C# does not implement this in the first place..
Impz0r
+7  A: 

There are a number of options in this case:

  1. Make the X and Y properties of your Point class immutable. That is, require the user to create a new Point whenever X or Y changes.
  2. Setup an event on the Point class and subscribe to it on the Position class. Whenever the Point's X or Y changes, fire the event. The Position class can handle side-effects in the event handler.

In this case, I would suggest option #1

Tom Cabanski
A third variant, if you need to update X and Y very often, would be to abandon the Point class entirely and have two properties PositionX and PositionY on the class. In this case it's more efficient than creating a new object/firing an event every time something changes.
frenetisch applaudierend
Excellent point!
Tom Cabanski
Instead of your first propsition, I think one would be better to use a struct for the Point class.
Danvil
Making the Point class an immutable struct solve all sorts of problems. What made me a convert was Bill Wagner's 'Effective C# book' - 'Item 7: Prefer Immutable Atomic Value Types'. Also, Bill makes the case for struct vs. class in his blog: http://srtsolutions.com/public/item/251137
Mark Booth
Incidentally, this original question is dealt with very well by Wagner in in 'Effective C#' - 'Item 23: Avoid Returning References to Internal Class Objects'.
Mark Booth
+1  A: 

1) Make Point.X and Point.Y private. 2) Add properties for X and Y to Point. 3) Add an event to Point that is raised when either X or Y are modified. 4) Register Control as a listener for the events that are raised by Point.

Seventh Element
+2  A: 

The statement myControl.Position.X = 1.0f; actually calls the getter and not the setter of your Position property. A way to do what you want to do could be by exposing the X and Y values directly on your class, like so:

public class Control  
{  
 protected Point m_Position = new Point();  

 public float PositionX
 {  
  get { return m_Position.X; }  
  set   
  {   
    m_Position.X = value; }  
    // reorganize internal structure..  
    reorganize();  
  }  

  ... Same thing for PositionY

  protected reorganize()  
  {  
   // do some stuff  
  }  
}

Another way would be to implement some event on the Position class that is raised every time X or Y change. This would entail making X and Y into properties on the Point object, and raising an event each time they are changed. Your control would then have to subscribe to that event.

klausbyskov
This does indeed work, but then i can't use Position directly anymore which i try to keep :)
Impz0r